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