package Pitonyak::DeepCopy; #************************************************************ =head1 NAME Pitonyak::DeepCopy - Copy an object reference with new copies, even if it contains references. =head1 SYNOPSIS C C =head1 DESCRIPTION Assume the hash A% contains a hash. Now, copy the elements from A% into B%. The obvious solution enumerates the keys and assigns the value from A% to B%. Something like this: C Unfortunately, the contained hash is a reference, %A and %B both reference the same hash. In other words, if you modify the contained hash in %A or %B, you change it in both. The proper solution is obtained using C =head1 COPYRIGHT Copyright 1998-2009, Andrew Pitonyak This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 Modification History =head2 September 01, 2002 Version 1.00 First release =head2 September 10, 2002 Version 1.01 Changed internal documentation to POD documentation. Added parameter checking. =head2 January 18, 2007 Version 1.02 Updated POD and reformatted. =head2 January 18, 2007 Version 1.03 Removed reference to Carp library, because it is not used. =head1 Methods =cut require Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); $VERSION = '1.03'; @ISA = qw(Exporter); @EXPORT = qw(); @EXPORT_OK = qw(deep_copy); use strict; #************************************************************ =pod =head2 deep_copy =over 4 =item C<< deep_copy(ref_to_object) >> Accept a reference to an object and return a reference to a new copy of the object. C<$copy_ref = deep_copy(\%hash_ref);> =back =cut #************************************************************ sub deep_copy { # if not defined then return it return undef if $#_ < 0 || !defined( $_[0] ); # if not a reference then return the parameter return $_[0] if !ref( $_[0] ); my $obj = shift; if ( UNIVERSAL::isa( $obj, 'SCALAR' ) ) { my $temp = deepcopy($$obj); return \$temp; } elsif ( UNIVERSAL::isa( $obj, 'HASH' ) ) { my $temp_hash = {}; foreach my $key ( keys %$obj ) { if ( !defined( $obj->{$key} ) || !ref( $obj->{$key} ) ) { $temp_hash->{$key} = $obj->{$key}; } else { $temp_hash->{$key} = deep_copy( $obj->{$key} ); } } return $temp_hash; } elsif ( UNIVERSAL::isa( $obj, 'ARRAY' ) ) { my $temp_array = []; foreach my $array_val (@$obj) { if ( !defined($array_val) || !ref($array_val) ) { push ( @$temp_array, $array_val ); } else { push ( @$temp_array, deep_copy($array_val) ); } } return $temp_array; } # ?? I am uncertain about this one elsif ( UNIVERSAL::isa( $obj, 'REF' ) ) { my $temp = deepcopy($$obj); return \$temp; } # I guess that it is either CODE, GLOB or LVALUE else { return $obj; } } 1;