Switch benchmarker to Dumbbench, cleanup
[p5sagit/Class-Accessor-Grouped.git] / lib / Class / Accessor / Grouped.pm
CommitLineData
963a69a5 1package Class::Accessor::Grouped;
2use strict;
3use warnings;
a0bce8bc 4use Carp ();
a0bce8bc 5use Scalar::Util ();
6d0e8ff2 6use Module::Runtime ();
df845078 7
8BEGIN {
6d0e8ff2 9 # use M::R to work around the 5.8 require bugs
df845078 10 if ($] < 5.009_005) {
6d0e8ff2 11 Module::Runtime::require_module('MRO::Compat');
df845078 12 }
13 else {
14 require mro;
15 }
16}
331e820d 17
ad0ed975 18our $VERSION = '0.10006';
d93670a5 19$VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
963a69a5 20
80ebe3b6 21# when changing minimum version don't forget to adjust Makefile.PL as well
85ccab9a 22our $__minimum_xsa_version;
80ebe3b6 23BEGIN { $__minimum_xsa_version = '1.13' }
9f562456 24
8019c4d8 25our $USE_XS;
26# the unless defined is here so that we can override the value
27# before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
28$USE_XS = $ENV{CAG_USE_XS}
ba8c183b 29 unless defined $USE_XS;
af169484 30
6d0e8ff2 31BEGIN {
32 package __CAG_ENV__;
33
34 die "Huh?! No minimum C::XSA version?!\n"
35 unless $__minimum_xsa_version;
36
37 local $@;
38 require constant;
39
40 # individual (one const at a time) imports so we are 5.6.2 compatible
41 # if we can - why not ;)
42 constant->import( NO_SUBNAME => eval {
43 Module::Runtime::require_module('Sub::Name')
44 } ? 0 : "$@" );
45
46 constant->import( NO_CXSA => ( !NO_SUBNAME() and eval {
47 Module::Runtime::use_module('Class::XSAccessor' => $__minimum_xsa_version)
48 } ) ? 0 : "$@" );
49
50 constant->import( BROKEN_GOTO => ($] < '5.008009') ? 1 : 0 );
51
52 constant->import( UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0 );
53
54 constant->import( TRACK_UNDEFER_FAIL => (
55 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
56 and
57 $0 =~ m|^ x?t / .+ \.t $|x
58 ) ? 1 : 0 );
59}
60
8079caeb 61# Yes this method is undocumented
85ccab9a 62# Yes it should be a private coderef like all the rest at the end of this file
8079caeb 63# No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
64# %$*@!?&!&#*$!!!
65sub _mk_group_accessors {
ba8c183b 66 my($self, $maker, $group, @fields) = @_;
67 my $class = Scalar::Util::blessed $self || $self;
eece2562 68
ba8c183b 69 no strict 'refs';
70 no warnings 'redefine';
eece2562 71
ba8c183b 72 # So we don't have to do lots of lookups inside the loop.
73 $maker = $self->can($maker) unless ref $maker;
eece2562 74
ba8c183b 75 for (@fields) {
eece2562 76
ba8c183b 77 my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
eece2562 78
33fe2299 79 for (qw/DESTROY AUTOLOAD CLONE/) {
80 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
81 if $name eq $_;
82 }
83
ba8c183b 84 my $alias = "_${name}_accessor";
eece2562 85
ba8c183b 86 for my $meth ($name, $alias) {
eece2562 87
ba8c183b 88 # the maker may elect to not return anything, meaning it already
89 # installed the coderef for us (e.g. lack of Sub::Name)
90 my $cref = $self->$maker($group, $field, $meth)
91 or next;
eece2562 92
ba8c183b 93 my $fq_meth = "${class}::${meth}";
eece2562 94
ba8c183b 95 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
96 #unless defined &{$class."\:\:$field"}
eece2562 97 }
ba8c183b 98 }
eece2562 99};
100
85ccab9a 101# coderef is setup at the end for clarity
102my $gen_accessor;
eece2562 103
963a69a5 104=head1 NAME
105
1ad8d8c6 106Class::Accessor::Grouped - Lets you build groups of accessors
963a69a5 107
108=head1 SYNOPSIS
109
3b118c10 110 use base 'Class::Accessor::Grouped';
111
112 # make basic accessors for objects
113 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
114
115 # make accessor that works for objects and classes
116 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
117
963a69a5 118=head1 DESCRIPTION
119
120This class lets you build groups of accessors that will call different
121getters and setters.
122
123=head1 METHODS
124
125=head2 mk_group_accessors
126
8e0a387b 127 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
18922520 128
963a69a5 129=over 4
130
131=item Arguments: $group, @fieldspec
132
133Returns: none
134
135=back
136
137Creates a set of accessors in a given group.
138
139$group is the name of the accessor group for the generated accessors; they
140will call get_$group($field) on get and set_$group($field, $value) on set.
141
22fa6720 142If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
143to tell Class::Accessor::Grouped to use its own get_simple and set_simple
144methods.
145
963a69a5 146@fieldspec is a list of field/accessor names; if a fieldspec is a scalar
147this is used as both field and accessor name, if a listref it is expected to
148be of the form [ $accessor, $field ].
149
150=cut
151
152sub mk_group_accessors {
ba8c183b 153 my ($self, $group, @fields) = @_;
963a69a5 154
ba8c183b 155 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
156 return;
963a69a5 157}
158
963a69a5 159=head2 mk_group_ro_accessors
160
8e0a387b 161 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
18922520 162
963a69a5 163=over 4
164
165=item Arguments: $group, @fieldspec
166
167Returns: none
168
169=back
170
171Creates a set of read only accessors in a given group. Identical to
a557f8ad 172L</mk_group_accessors> but accessors will throw an error if passed a value
963a69a5 173rather than setting the value.
174
175=cut
176
177sub mk_group_ro_accessors {
ba8c183b 178 my($self, $group, @fields) = @_;
963a69a5 179
ba8c183b 180 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
963a69a5 181}
182
183=head2 mk_group_wo_accessors
184
8e0a387b 185 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
18922520 186
963a69a5 187=over 4
188
189=item Arguments: $group, @fieldspec
190
191Returns: none
192
193=back
194
195Creates a set of write only accessors in a given group. Identical to
a557f8ad 196L</mk_group_accessors> but accessors will throw an error if not passed a
963a69a5 197value rather than getting the value.
198
199=cut
200
201sub mk_group_wo_accessors {
ba8c183b 202 my($self, $group, @fields) = @_;
963a69a5 203
ba8c183b 204 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
963a69a5 205}
206
963a69a5 207=head2 get_simple
208
209=over 4
210
211=item Arguments: $field
212
213Returns: $value
214
215=back
216
217Simple getter for hash-based objects which returns the value for the field
218name passed as an argument.
219
220=cut
221
222sub get_simple {
ba8c183b 223 return $_[0]->{$_[1]};
963a69a5 224}
225
226=head2 set_simple
227
228=over 4
229
230=item Arguments: $field, $new_value
231
232Returns: $new_value
233
234=back
235
236Simple setter for hash-based objects which sets and then returns the value
237for the field name passed as an argument.
238
239=cut
240
241sub set_simple {
ba8c183b 242 return $_[0]->{$_[1]} = $_[2];
963a69a5 243}
244
e6f2a0fd 245
246=head2 get_inherited
247
248=over 4
249
250=item Arguments: $field
251
252Returns: $value
253
254=back
255
331e820d 256Simple getter for Classes and hash-based objects which returns the value for
257the field name passed as an argument. This behaves much like
258L<Class::Data::Accessor> where the field can be set in a base class,
259inherited and changed in subclasses, and inherited and changed for object
260instances.
e6f2a0fd 261
262=cut
263
264sub get_inherited {
ba8c183b 265 my $class;
266
267 if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
268 if (Scalar::Util::reftype $_[0] eq 'HASH') {
269 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
62cf9924 270 }
271 else {
ba8c183b 272 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
62cf9924 273 }
ba8c183b 274 }
275 else {
276 $class = $_[0];
277 }
e6f2a0fd 278
ba8c183b 279 no strict 'refs';
280 no warnings 'uninitialized';
62cf9924 281
ba8c183b 282 my $cag_slot = '::__cag_'. $_[1];
283 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
e6f2a0fd 284
ba8c183b 285 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
286 my $cur_gen = mro::get_pkg_gen ($class);
287 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
288 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
289 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
290 }
a49c32d9 291
ba8c183b 292 for (@{$class.'::__cag_supers__'}) {
293 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
294 };
c46050d3 295
ba8c183b 296 return undef;
e6f2a0fd 297}
298
299=head2 set_inherited
300
301=over 4
302
303=item Arguments: $field, $new_value
304
305Returns: $new_value
306
307=back
308
331e820d 309Simple setter for Classes and hash-based objects which sets and then returns
310the value for the field name passed as an argument. When called on a hash-based
311object it will set the appropriate hash key value. When called on a class, it
312will set a class level variable.
e6f2a0fd 313
331e820d 314B<Note:>: This method will die if you try to set an object variable on a non
315hash-based object.
e6f2a0fd 316
317=cut
318
319sub set_inherited {
ba8c183b 320 if (defined Scalar::Util::blessed $_[0]) {
321 if (Scalar::Util::reftype $_[0] eq 'HASH') {
322 return $_[0]->{$_[1]} = $_[2];
e6f2a0fd 323 } else {
ba8c183b 324 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
e6f2a0fd 325 };
ba8c183b 326 } else {
327 no strict 'refs';
328
329 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
330 };
e6f2a0fd 331}
332
331e820d 333=head2 get_component_class
334
335=over 4
336
337=item Arguments: $field
338
339Returns: $value
340
341=back
342
343Gets the value of the specified component class.
344
ba8c183b 345 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
97d76fb4 346
ba8c183b 347 $self->result_class->method();
97d76fb4 348
ba8c183b 349 ## same as
350 $self->get_component_class('result_class')->method();
331e820d 351
352=cut
353
354sub get_component_class {
ba8c183b 355 return $_[0]->get_inherited($_[1]);
331e820d 356};
357
358=head2 set_component_class
359
360=over 4
361
362=item Arguments: $field, $class
363
364Returns: $new_value
365
366=back
367
368Inherited accessor that automatically loads the specified class before setting
369it. This method will die if the specified class could not be loaded.
370
ba8c183b 371 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
372 __PACKAGE__->result_class('MyClass');
97d76fb4 373
ba8c183b 374 $self->result_class->method();
331e820d 375
376=cut
377
378sub set_component_class {
6d0e8ff2 379 if (defined $_[2] and length $_[2]) {
380 # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
381 # module loading
382 local ($^W, $_);
383
384 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
385 my $err;
386 {
387 local $@;
388 eval { Module::Runtime::use_package_optimistically($_[2]) }
389 or $err = $@;
390 }
391 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
ba8c183b 392
6d0e8ff2 393 }
394 else {
395 eval { Module::Runtime::use_package_optimistically($_[2]) }
396 or Carp::croak("Could not load $_[1] '$_[2]': $@");
397 }
ba8c183b 398 };
331e820d 399
ba8c183b 400 return $_[0]->set_inherited($_[1], $_[2]);
331e820d 401};
402
8e0a387b 403=head1 INTERNAL METHODS
404
405These methods are documented for clarity, but are never meant to be called
406directly, and are not really meant for overriding either.
407
a49c32d9 408=head2 get_super_paths
409
8e0a387b 410Returns a list of 'parent' or 'super' class names that the current class
411inherited from. This is what drives the traversal done by L</get_inherited>.
a49c32d9 412
413=cut
414
415sub get_super_paths {
ba8c183b 416 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
a49c32d9 417};
418
8e0a387b 419=head2 make_group_accessor
420
421 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
422 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
423
424=over 4
425
426=item Arguments: $group, $field, $accessor
427
428Returns: \&accessor_coderef ?
429
430=back
431
432Called by mk_group_accessors for each entry in @fieldspec. Either returns
433a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
434C<undef> if it elects to install the coderef on its own.
435
436=cut
437
438sub make_group_accessor { $gen_accessor->('rw', @_) }
439
440=head2 make_group_ro_accessor
441
442 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
443 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
444
445=over 4
446
447=item Arguments: $group, $field, $accessor
448
449Returns: \&accessor_coderef ?
450
451=back
452
453Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
454a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
455C<undef> if it elects to install the coderef on its own.
456
457=cut
458
459sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
460
461=head2 make_group_wo_accessor
462
463 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
464 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
465
466=over 4
467
468=item Arguments: $group, $field, $accessor
469
470Returns: \&accessor_coderef ?
471
472=back
473
474Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
475a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
476C<undef> if it elects to install the coderef on its own.
477
478=cut
479
480sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
481
482
9d7d52da 483=head1 PERFORMANCE
15cf8e32 484
8019c4d8 485To provide total flexibility L<Class::Accessor::Grouped> calls methods
486internally while performing get/set actions, which makes it noticeably
487slower than similar modules. To compensate, this module will automatically
488use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
b36cd259 489accessors if this module is available on your system.
8019c4d8 490
491=head2 Benchmark
492
493This is the result of a set/get/set loop benchmark on perl 5.12.1 with
494thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
af71d687 495L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
496L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
497
498 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
499 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
500 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
501 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
502 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
503 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
504 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
505 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
506 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
507 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
508 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
509 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
510 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
8019c4d8 511
512Benchmark program is available in the root of the
513L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
514
515=head2 Notes on Class::XSAccessor
516
bd83e674 517You can force (or disable) the use of L<Class::XSAccessor> before creating a
518particular C<simple> accessor by either manipulating the global variable
519C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
520L<localization|perlfunc/local>, or you can do so before runtime via the
521C<CAG_USE_XS> environment variable.
522
523Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
524L</set_simple> this module does its best to detect if you are overriding
525one of these methods and will fall back to using the perl version of the
526accessor in order to maintain consistency. However be aware that if you
527enable use of C<Class::XSAccessor> (automatically or explicitly), create
528an object, invoke a simple accessor on that object, and B<then> manipulate
529the symbol table to install a C<get/set_simple> override - you get to keep
530all the pieces.
531
963a69a5 532=head1 AUTHORS
533
534Matt S. Trout <mst@shadowcatsystems.co.uk>
ba6f7b1b 535
97972dcb 536Christopher H. Laco <claco@chrislaco.com>
963a69a5 537
8ef9b3ff 538=head1 CONTRIBUTORS
dfb86526 539
ba6f7b1b 540Caelum: Rafael Kitover <rkitover@cpan.org>
541
3b118c10 542frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
543
8ef9b3ff 544groditi: Guillermo Roditi <groditi@cpan.org>
ba6f7b1b 545
6a4c729f 546Jason Plum <jason.plum@bmmsi.com>
dfb86526 547
ba6f7b1b 548ribasushi: Peter Rabbitson <ribasushi@cpan.org>
549
550
4fe25633 551=head1 COPYRIGHT & LICENSE
963a69a5 552
af169484 553Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
963a69a5 554
4fe25633 555This program is free software; you can redistribute it and/or modify
556it under the same terms as perl itself.
963a69a5 557
4fe25633 558=cut
85ccab9a 559
560########################################################################
561########################################################################
562########################################################################
563#
564# Here be many angry dragons
565# (all code is in private coderefs since everything inherits CAG)
566#
567########################################################################
568########################################################################
569
85ccab9a 570# Autodetect unless flag supplied
85ccab9a 571my $xsa_autodetected;
572if (! defined $USE_XS) {
3f6054c4 573 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
85ccab9a 574 $xsa_autodetected++;
575}
576
577my $maker_templates = {
578 rw => {
579 xs_call => 'accessors',
580 pp_code => sub {
98694bf0 581 my $set = "set_$_[0]";
582 my $get = "get_$_[0]";
583 my $field = $_[1];
85ccab9a 584 $field =~ s/'/\\'/g;
585
586 "
af71d687 587 \@_ != 1
85ccab9a 588 ? shift->$set('$field', \@_)
589 : shift->$get('$field')
590 "
591 },
592 },
593 ro => {
594 xs_call => 'getters',
595 pp_code => sub {
98694bf0 596 my $get = "get_$_[0]";
597 my $field = $_[1];
85ccab9a 598 $field =~ s/'/\\'/g;
599
600 "
601 \@_ == 1
602 ? shift->$get('$field')
603 : do {
604 my \$caller = caller;
98694bf0 605 my \$class = ref \$_[0] || \$_[0];
606 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
607 \"(read-only attributes of class '\$class')\");
85ccab9a 608 }
609 "
610 },
611 },
612 wo => {
613 xs_call => 'setters',
614 pp_code => sub {
98694bf0 615 my $set = "set_$_[0]";
616 my $field = $_[1];
85ccab9a 617 $field =~ s/'/\\'/g;
618
619 "
af71d687 620 \@_ != 1
85ccab9a 621 ? shift->$set('$field', \@_)
622 : do {
623 my \$caller = caller;
98694bf0 624 my \$class = ref \$_[0] || \$_[0];
625 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
626 \"(write-only attributes of class '\$class')\");
85ccab9a 627 }
628 "
629 },
630 },
631};
632
633
634my ($accessor_maker_cache, $no_xsa_warned_classes);
635
636# can't use pkg_gen to track this stuff, as it doesn't
637# detect superclass mucking
638my $original_simple_getter = __PACKAGE__->can ('get_simple');
639my $original_simple_setter = __PACKAGE__->can ('set_simple');
640
641# Note!!! Unusual signature
642$gen_accessor = sub {
643 my ($type, $class, $group, $field, $methname) = @_;
34051fe0 644 if (my $c = Scalar::Util::blessed( $class )) {
85ccab9a 645 $class = $c;
646 }
647
648 # When installing an XSA simple accessor, we need to make sure we are not
649 # short-circuiting a (compile or runtime) get_simple/set_simple override.
650 # What we do here is install a lazy first-access check, which will decide
651 # the ultimate coderef being placed in the accessor slot
f7cf6867 652 #
653 # Also note that the *original* class will always retain this shim, as
654 # different branches inheriting from it may have different overrides.
655 # Thus the final method (properly labeled and all) is installed in the
656 # calling-package's namespace
85ccab9a 657 if ($USE_XS and $group eq 'simple') {
3f6054c4 658 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
659 if __CAG_ENV__::NO_CXSA;
f7cf6867 660
de167379 661 my ($expected_cref, $cached_implementation);
662 my $ret = $expected_cref = sub {
f7cf6867 663 my $current_class = Scalar::Util::blessed( $_[0] ) || $_[0];
664
de167379 665 # $cached_implementation will be set only if the shim got
666 # 'around'ed, in which case it is handy to avoid re-running
667 # this block over and over again
668 my $resolved_implementation = $cached_implementation->{$current_class} || do {
669 if (
ad0ed975 670 ($current_class->can('get_simple')||0) == $original_simple_getter
de167379 671 &&
ad0ed975 672 ($current_class->can('set_simple')||0) == $original_simple_setter
de167379 673 ) {
674 # nothing has changed, might as well use the XS crefs
675 #
676 # note that by the time this code executes, we already have
677 # *objects* (since XSA works on 'simple' only by definition).
678 # If someone is mucking with the symbol table *after* there
679 # are some objects already - look! many, shiny pieces! :)
680 #
681 # The weird breeder thingy is because XSA does not have an
682 # interface returning *just* a coderef, without installing it
683 # anywhere :(
684 Class::XSAccessor->import(
685 replace => 1,
686 class => '__CAG__XSA__BREEDER__',
687 $maker_templates->{$type}{xs_call} => {
688 $methname => $field,
689 },
690 );
691 __CAG__XSA__BREEDER__->can($methname);
692 }
693 else {
694 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
695 # not using Carp since the line where this happens doesn't mean much
696 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
697 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
698 . "set_simple\n";
699 }
700
701 do {
702 # that's faster than local
703 $USE_XS = 0;
704 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
705 $USE_XS = 1;
706 $c;
707 };
708 }
709 };
710
711 # if after this shim was created someone wrapped it with an 'around',
712 # we can not blindly reinstall the method slot - we will destroy the
713 # wrapper. Silently chain execution further...
ad0ed975 714 if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
de167379 715
716 # there is no point in re-determining it on every subsequent call,
717 # just store for future reference
718 $cached_implementation->{$current_class} ||= $resolved_implementation;
719
720 # older perls segfault if the cref behind the goto throws
721 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
3f6054c4 722 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
de167379 723
724 goto $resolved_implementation;
725 }
726
3f6054c4 727 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
2d392af1 728 my $deferred_calls_seen = do {
729 no strict 'refs';
730 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
731 };
e6f2993f 732 my @cframe = caller(0);
2d392af1 733 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
e6f2993f 734 Carp::carp (
735 "Deferred version of method $cframe[3] invoked more than once (originally "
2d392af1 736 . "invoked at $already_seen). This is a strong indication your code has "
737 . 'cached the original ->can derived method coderef, and is using it instead '
738 . 'of the proper method re-lookup, causing performance regressions'
e6f2993f 739 );
740 }
741 else {
2d392af1 742 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
e6f2993f 743 }
744 }
745
de167379 746 # install the resolved implementation into the code slot so we do not
747 # come here anymore (hopefully)
748 # since XSAccessor was available - so is Sub::Name
749 {
e6f2993f 750 no strict 'refs';
751 no warnings 'redefine';
85ccab9a 752
f7cf6867 753 my $fq_name = "${current_class}::${methname}";
de167379 754 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
755
756 # need to update what the shim expects too *in case* its
757 # ->can was cached for some moronic reason
758 $expected_cref = $resolved_implementation;
759 Scalar::Util::weaken($expected_cref);
f7cf6867 760 }
85ccab9a 761
f7cf6867 762 # older perls segfault if the cref behind the goto throws
763 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
3f6054c4 764 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
85ccab9a 765
de167379 766 goto $resolved_implementation;
f7cf6867 767 };
de167379 768
769 Scalar::Util::weaken($expected_cref); # to break the self-reference
770 $ret;
85ccab9a 771 }
772
773 # no Sub::Name - just install the coderefs directly (compiling every time)
3f6054c4 774 elsif (__CAG_ENV__::NO_SUBNAME) {
eda06cc6 775 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
776 $maker_templates->{$type}{pp_code}->($group, $field);
777
fdb75175 778 no warnings 'redefine';
3f6054c4 779 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
bd975094 780 eval "sub ${class}::${methname} { $src }";
eda06cc6 781
e6f2993f 782 undef; # so that no further attempt will be made to install anything
85ccab9a 783 }
784
785 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
85ccab9a 786 else {
e6f2993f 787 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
eda06cc6 788 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
789 $maker_templates->{$type}{pp_code}->($group, $field);
790
3f6054c4 791 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
eda06cc6 792 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;
85ccab9a 793 })->()
794 }
795};
796
7971;