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