-
Notifications
You must be signed in to change notification settings - Fork 3
/
README
182 lines (148 loc) · 8.66 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
NAME
Class::Accessor::Inherited::XS - Fast XS inherited, object and class
accessors
SYNOPSIS
# install accessors at compile time
use Class::Accessor::Inherited::XS
package => 'Pkg', # optionally install into another package
constructor => 'new', # object constructor name
inherited => 'foo', # inherited accessor for class/object
object => 'foo', # non-inherited simple object accessor
varclass => 'foo', # non-inherited accessor for __PACKAGE__, aliased with '$__PACKAGE__::foo' variable
class => 'foo', # non-inherited anonymous accessor for __PACKAGE__
;
use Class::Accessor::Inherited::XS { # optional braces
inherited => {foo => 'foo_key'}, # change package variable/hash key
object => {foo => 'foo_key'}, # change hash key
class_ro => {foo => $default}, # class_ro, varclass_ro, class, varclass set default values instead
class => {foo => $subref}, # lazy accessor initializer
varclass => ['foo', 'bar'], # provide a list of accessor names
accessors => ['foo'], # alias for 'object'
getters => ['foo'], # alias for 'object_ro'
};
# Or if you prefer a Class::Accessor::Grouped-like interface, you can do it
# at run time. Note that this is not recommended and provides limited feature set.
use parent 'Class::Accessor::Inherited::XS::Compat';
__PACKAGE__->mk_inherited_accessors('foo', [bar => 'bar_key']);
__PACKAGE__->mk_class_accessors('foo');
__PACKAGE__->mk_varclass_accessors('foo');
__PACKAGE__->mk_object_accessors('foo');
DESCRIPTION
This module provides a very fast implementation for a wide range of
accessor types.
inherited accessors have been introduced by Class::Accessor::Grouped.
They allow you to override values set in a parent class with values set
in childs or object instances. This module tries to be compatible with
Class::Accessor::Grouped as much as possible.
Since this module focuses primary on speed, it provides no means to have
your own per-class getters/setters logic (like overriding
"get_inherited" in Class::Accessor::Grouped / "set_inherited" in
Class::Accessor::Grouped), but it allows you to create new inherited
accesor types with an attached callback.
class and varclass accessors are non-inherited package accessors - they
return values from the class they were defined in, even when called on
objects or child classes. The difference between them is that the
varclass internal storage is a package variable with the same name,
while class stores it's value in an anonymous variable.
object accessors provides plain simple hash key access.
class_ro, varclass_ro, inherited_ro, object_ro are readonly counterparts
for correspoding accessors without _ro suffix. They behave exactly the
same except that they will croak upon a call with arguments. To set
values for such accessors, you can write to either corresponding package
variable or a hash key. ro_class accessor has no externally accessible
storage, but you can provide a default value for it using hash
initializer syntax.
lazy accessors do not have their own keyword but, instead, if you pass a
subref as a default argument to any one of the package accessors'
family, it's not stored as-is, but is called instead upon the first
accessor read and it's return value is stored. After that, lazy accessor
becomes a normal one of the same type. Calling an accessor as a setter
before first getter will loose it's defaultness (unless, of course, it's
a readonly one).
constructor can create objects either from a list or from a single
hashref. Note that if you pass a hash reference, it becomes blessed too.
If that's not what you want, pass a dereferenced copy. As a special
case, passing a single undef returns you an empty object.
__PACKAGE__->new(foo => 1, bar => 2); # values are copied
__PACKAGE__->new(\%args); # values are not copied, much faster
$obj->new(foo => 1, bar => 2); # values are copied, but nothing is taken from $obj
$obj->new(\%args); # values are not copied, and nothing is taken from $obj
UTF-8 AND BINARY SAFETY
Starting with the perl 5.16.0, this module provides full support for
UTF-8 method names and hash keys. But on older perls you can't
distinguish UTF-8 strings from bytes string in method names, so
accessors with UTF-8 names can end up getting a wrong value. You have
been warned.
Also, starting from 5.16.0 accessor installation is binary safe, except
for the Windows platform. This module croaks on attempts to install
binary accessors on unsupported platforms.
THREADS
Though highly discouraged, perl threads are supported by
Class::Accessor::Inherited::XS. You can have accessors with same names
pointing to different keys in different threads, etc. There are no known
conceptual leaks.
PERFORMANCE
Class::Accessor::Inherited::XS is at least 10x times faster than
Class::Accessor::Grouped, depending on your usage pattern. Inherited
accessors have constant speed even in large inheritance chains. Object
accessors are even faster than Class::XSAccessor ones.
Accessors with just an empty sub callback are ~3x times slower then
normal ones, so use them only when absolutely necessary.
You can see some benchmarks by running bench/bench.pl
EXTENDING
package MyAccessor;
# 'register_type' isn't exported
use Class::Accessor::Inherited::XS::Constants;
Class::Accessor::Inherited::XS::register_type(
inherited_cb => {on_read => sub {}, on_write => sub{}, opts => $bitset},
);
package MyClass;
use MyAccessor;
use Class::Accessor::Inherited::XS {
inherited => ['foo'],
inherited_cb => ['bar'],
};
You can register new inherited accessor types with associated read/write
callbacks. Unlike Class::Accessor::Grouped, only a single callback can
be set for a type, without per-class get_$type/set_$type lookups. You
can omit either on_read or on_write if you don't need it to avoid
performance losses from associated call.
on_read callback receives a single argument - return value from the
underlying inherited accessor. It's result is the new accessor's return
value (and it isn't stored anywhere).
on_write callback receives original accessor's arguments, and it's
return value is stored as usual. Exceptions thrown from this callback
will cancel store and will leave old value unchanged.
You can specify additional flags with the 'opts' key. Currently only
IsNamed is supported - with it the accessor callback is invoked with
it's name passed as an additional argument. This can be useful when
creating a proxy.
PROFILING WITH Devel::NYTProf
To perform it's task, Devel::NYTProf hooks into the perl interpreter by
replacing default behaviour for subroutine calls at the opcode level. To
squeeze last bits of performance, Class::Accessor::Inherited::XS does
the same, but separately on each call site of its accessors. It turns
out into CAIX favor - Devel::NYTProf sees only the first call to CAIX
accessor, but all subsequent ones become invisible to the subs profiler.
Note that the statement profiler still correctly accounts for the time
spent on each line, you just don't see time spent in accessors' calls
separately. That's sometimes OK, sometimes not - you get profile with
all possible optimizations on, but it's not easy to comprehend.
Since it's hard to detect Devel::NYTProf (and any other module doing
such magic) in a portable way (all hail Win32), there's an %ENV switch
available - you can set CAIXS_DISABLE_ENTERSUB to a true value to
disable opcode optimizations and get a full subs profile.
CAVEATS
When using varclass accessors, do not clear or alias
*__PACKAGE__::accessor glob - that will break aliasing between accessor
storage and $__PACKAGE__::accessor variable. While the stored value is
still accessible through accessor, it effectively becomes a class one.
SEE ALSO
* Class::Accessor::Grouped
* Class::XSAccessor
COPYRIGHT AND LICENSE
Copyright (C) 2009 by Vladimir Timofeev
Copyright (C) 2014-2018 by Sergey Aleynikov
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself, either Perl version 5.10.1 or, at
your option, any later version of Perl 5 you may have available.