line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package Class::Cloneable; |
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
30758
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
39
|
|
5
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
80
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
sub clone { |
10
|
4
|
|
|
4
|
1
|
20975
|
my ($self) = @_; |
11
|
4
|
|
|
|
|
11
|
return Class::Cloneable::Util::clone($self); |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
package Class::Cloneable::Util; |
15
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
14
|
|
|
1
|
|
|
|
|
29
|
|
17
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
4129
|
use overload (); |
|
1
|
|
|
|
|
937
|
|
|
1
|
|
|
|
|
20
|
|
20
|
1
|
|
|
1
|
|
5
|
use Carp qw(confess); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
74
|
|
21
|
1
|
|
|
1
|
|
4
|
use Scalar::Util qw(blessed reftype weaken isweak); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
783
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub clone { |
26
|
60
|
100
|
100
|
60
|
|
20586
|
(UNIVERSAL::isa((caller)[0], 'Class::Cloneable') || |
27
|
|
|
|
|
|
|
UNIVERSAL::isa((caller)[0], 'Class::Cloneable::Util')) |
28
|
|
|
|
|
|
|
|| confess "Illegal Operation : This method can only be called by a subclass of Class::Cloneable"; |
29
|
58
|
|
|
|
|
115
|
my ($to_clone, $cache) = @_; |
30
|
58
|
100
|
|
|
|
312
|
(defined($to_clone)) |
31
|
|
|
|
|
|
|
|| confess "Insufficient Arguments : Must specify the object to clone"; |
32
|
|
|
|
|
|
|
# To start with, non-reference values are |
33
|
|
|
|
|
|
|
# not copied, just returned, cache or not |
34
|
57
|
100
|
|
|
|
117
|
return $to_clone unless ref($to_clone); |
35
|
|
|
|
|
|
|
# now check for an active cache |
36
|
52
|
100
|
|
|
|
89
|
unless(defined $cache) { |
37
|
|
|
|
|
|
|
# now we check to see what we have, |
38
|
|
|
|
|
|
|
# and deconstruct and deep copy the |
39
|
|
|
|
|
|
|
# top-level Class::Cloneable objects |
40
|
6
|
100
|
100
|
|
|
65
|
if (blessed($to_clone) && $to_clone->isa('Class::Cloneable')) { |
41
|
|
|
|
|
|
|
# now copy the object's internals and |
42
|
|
|
|
|
|
|
# bless the new clone into the right class |
43
|
|
|
|
|
|
|
# storing it in the cache case we run |
44
|
|
|
|
|
|
|
# into a circular ref |
45
|
4
|
|
|
|
|
20
|
return $cache->{$to_clone} = bless( |
46
|
|
|
|
|
|
|
cloneRef($to_clone, ($cache = {}), reftype($to_clone)), |
47
|
|
|
|
|
|
|
blessed($to_clone) |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
# if it is not a Class::Cloneable, then |
51
|
|
|
|
|
|
|
# we just proceed as normal |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
# if we have it in the cache them return the cached clone |
54
|
48
|
100
|
|
|
|
142
|
return $cache->{$to_clone} if exists $cache->{$to_clone}; |
55
|
|
|
|
|
|
|
# now try it as an object, which will in |
56
|
|
|
|
|
|
|
# turn try it as ref if its not an object |
57
|
|
|
|
|
|
|
# now store it in case we run into a circular ref |
58
|
44
|
|
|
|
|
77
|
return $cache->{$to_clone} = cloneObject($to_clone, $cache); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub cloneObject { |
62
|
51
|
100
|
100
|
51
|
|
5219
|
(UNIVERSAL::isa((caller)[0], 'Class::Cloneable') || |
63
|
|
|
|
|
|
|
UNIVERSAL::isa((caller)[0], 'Class::Cloneable::Util')) |
64
|
|
|
|
|
|
|
|| confess "Illegal Operation : This method can only be called by a subclass of Class::Cloneable"; |
65
|
49
|
|
|
|
|
90
|
my ($to_clone, $cache) = @_; |
66
|
49
|
100
|
100
|
|
|
1139
|
(ref($to_clone) && (ref($cache) && ref($cache) eq 'HASH')) |
|
|
|
66
|
|
|
|
|
67
|
|
|
|
|
|
|
|| confess "Insufficient Arguments : Must specify the object to clone and a valid cache"; |
68
|
|
|
|
|
|
|
# check to see if we have an Class::Cloneable object, |
69
|
|
|
|
|
|
|
# or check to see if its an object, with a clone method |
70
|
44
|
100
|
|
|
|
118
|
if (blessed($to_clone)) { |
71
|
|
|
|
|
|
|
# note, we want to be sure to respect any overriding of |
72
|
|
|
|
|
|
|
# the clone method with Class::Cloneable objects here |
73
|
|
|
|
|
|
|
# otherwise it would be faster to just send it directly |
74
|
|
|
|
|
|
|
# to the Class::Cloneable::Util::clone function above |
75
|
9
|
100
|
|
|
|
90
|
return $cache->{$to_clone} = ($to_clone->can('clone') ? |
76
|
|
|
|
|
|
|
$to_clone->clone() |
77
|
|
|
|
|
|
|
: |
78
|
|
|
|
|
|
|
# or if we have an object, with no clone method, then |
79
|
|
|
|
|
|
|
# we will respect its encapsulation, and not muck with |
80
|
|
|
|
|
|
|
# its internals. Basically, we assume it does not want |
81
|
|
|
|
|
|
|
# to be cloned |
82
|
|
|
|
|
|
|
$to_clone); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
# if all else fails, it is likely a basic ref |
85
|
35
|
|
|
|
|
66
|
return $cache->{$to_clone} = cloneRef($to_clone, $cache); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub cloneRef { |
89
|
46
|
100
|
100
|
46
|
|
4981
|
(UNIVERSAL::isa((caller)[0], 'Class::Cloneable') || |
90
|
|
|
|
|
|
|
UNIVERSAL::isa((caller)[0], 'Class::Cloneable::Util')) |
91
|
|
|
|
|
|
|
|| confess "Illegal Operation : This method can only be called by a subclass of Class::Cloneable"; |
92
|
44
|
|
|
|
|
149
|
my ($to_clone, $cache, $ref_type) = @_; |
93
|
44
|
100
|
100
|
|
|
1107
|
(ref($to_clone) && (ref($cache) && ref($cache) eq 'HASH')) |
|
|
|
66
|
|
|
|
|
94
|
|
|
|
|
|
|
|| confess "Insufficient Arguments : Must specify the object to clone and a valid cache"; |
95
|
39
|
100
|
|
|
|
83
|
$ref_type = ref($to_clone) unless defined $ref_type; |
96
|
|
|
|
|
|
|
# check if it is weakened |
97
|
39
|
|
|
|
|
53
|
my $is_weak; |
98
|
39
|
50
|
|
|
|
99
|
$is_weak = 1 if isweak($to_clone); |
99
|
39
|
|
|
|
|
36
|
my ($clone, $tied); |
100
|
39
|
100
|
100
|
|
|
107
|
if ($ref_type eq 'HASH') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
101
|
16
|
|
|
|
|
22
|
$clone = {}; |
102
|
16
|
100
|
|
|
|
19
|
tie %{$clone}, ref $tied if $tied = tied(%{$to_clone}); |
|
2
|
|
|
|
|
10
|
|
|
16
|
|
|
|
|
42
|
|
103
|
16
|
100
|
|
|
|
26
|
%{$clone} = map { ref($_) ? clone($_, $cache) : $_ } %{$to_clone}; |
|
16
|
|
|
|
|
66
|
|
|
92
|
|
|
|
|
218
|
|
|
16
|
|
|
|
|
46
|
|
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
elsif ($ref_type eq 'ARRAY') { |
106
|
13
|
|
|
|
|
21
|
$clone = []; |
107
|
13
|
100
|
|
|
|
25
|
tie @{$clone}, ref $tied if $tied = tied(@{$to_clone}); |
|
2
|
|
|
|
|
12
|
|
|
13
|
|
|
|
|
39
|
|
108
|
13
|
100
|
|
|
|
19
|
@{$clone} = map { ref($_) ? clone($_, $cache) : $_ } @{$to_clone}; |
|
13
|
|
|
|
|
37
|
|
|
20
|
|
|
|
|
43
|
|
|
13
|
|
|
|
|
31
|
|
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
elsif ($ref_type eq 'REF' or $ref_type eq 'SCALAR') { |
111
|
6
|
|
|
|
|
9
|
my $var = ""; |
112
|
6
|
|
|
|
|
7
|
$clone = \$var; |
113
|
6
|
100
|
|
|
|
7
|
tie ${$clone}, ref $tied if $tied = tied(${$to_clone}); |
|
2
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
24
|
|
114
|
6
|
|
|
|
|
16
|
${$clone} = clone(${$to_clone}, $cache); |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
13
|
|
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
else { |
117
|
|
|
|
|
|
|
# shallow copy reference to code, glob, regex |
118
|
4
|
|
|
|
|
5
|
$clone = $to_clone; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
# store it in our cache |
121
|
39
|
|
|
|
|
132
|
$cache->{$to_clone} = $clone; |
122
|
|
|
|
|
|
|
# and weaken it if appropriate |
123
|
39
|
50
|
|
|
|
588
|
weaken($clone) if $is_weak; |
124
|
|
|
|
|
|
|
# and return the clone |
125
|
39
|
|
|
|
|
202
|
return $clone; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
1; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
__END__ |