Solved

Clean way to copy a Perl hash through Perl 5 API

Posted on 2004-08-26
7
4,787 Views
Last Modified: 2008-01-09

I have a variable HV *myHash - which may be a simple Perl hash, an object or a tied variable. I want to make a copy of it (its variables) into a new variable myHash2, and destroy it afterwards.  

I just need two functions that are proven to work fine (and are very safe) for copying/deleting. Clean/short solutions would really be appreciated.
0
Comment
Question by:kushcu
7 Comments
 
LVL 84

Expert Comment

by:ozo
ID: 11908855
#A shallow copy of a hash can be done with
%newhash = %oldhash;
0
 

Author Comment

by:kushcu
ID: 11908863
yes, but I'm not in the Perl domain. My answer would probably include hv_iterinit and hv_iternext and some functions to fetch/delete data.
0
 

Author Comment

by:kushcu
ID: 11908865
And I need a deep copy.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 48

Expert Comment

by:Tintin
ID: 11909343
I must admit I wasn't aware of what shallow/deep copying was.

Perhaps the following article will be useful.

http://www.stonehenge.com/merlyn/UnixReview/col30.html
0
 
LVL 3

Accepted Solution

by:
terageek earned 125 total points
ID: 11916152
To deep copy tied and/or blessed values it is a bit complex.  The code below should also copy duplicate references as duplicate references and circular references as circular references without going into an infinite loop.

my %copied_refs;
sub deep_copy {
    my @ret_val = &_deep_copy(@_);
    undef %copied_refs;
    return @ret_val;
}

sub _deep_copy {
    my @copyAr;
    foreach (@_) {
        my $copy;
        if (blessed $_) {
            $copy = &_deep_copy(blessed $_);
            bless $copy, ref blessed $_;
        } elsif (tied $_) {
            tie $copy, ref tied $_;
            if ((tied $_)->isa("HASH")) {
                %{tied $copy} = %{&_deep_copy(tied $_)};
            } elsif ((tied $_[0])->isa("ARRAY")) {
                @{tied $copy} = @{&_deep_copy(tied $_)};
            } else {
                ${tied $copy} = ${&_deep_copy(tied $_)};
            }
        } elsif (ref $_) {
            if (exists $copied_refs{$_}) {
              # For circular and duplicate references, return a
              # pointer to the previously made copy.  For cirular
              # references this avoids an infinite loop, and
              # creates a circular reference.  For duplicate
              # references, this will create a duplicate reference
                push @copyAr, ${$copied_refs{$_}};
                next;
            } else {
              # If this is a reference, save it and a pointer
              # to the copy so circular references and duplicate
              # references can be copied accurately
                $copied_refs{$_} = \$copy;
            }
       
            if (ref($_) eq "HASH") {
                while (my ($key, $value) = each %$_) {
                    $_->{$key} = &_deep_copy($value);
                }
                foreach
            } elsif (ref($_)eq "ARRAY") {
                $copy = [&_deep_copy(@$_)];
            } elsif (ref($_)eq "SCALAR") {
                $copy = &_deep_copy($$_);
                $copy = \$copy;
            } else {
                $copy = $_;
            }
        } else {
            $copy = $_;
        }
        push @copyAr, $copy;
    }
    return @copyAr;
}

Deep delete...

undef *myHash;

Perl will handle doing a deep delete for you in most cases.  The only time perl has an issue with garbage collection is when you have circular references.  If you have multiple pointers to the same object, Perl will also not delete the object, however you usually don't want it to be deleted in that case.  You can try to write a deep delete function to take care of circular references, but you won't be able to tell if you are messing up a second reference to one of the contained objects. For example...

%a = (a => 1);
%b = (b => \%a, c => {c => 2});

If you attempt to deep delete %b, you will destroy %a.  If you let perl do it, the hash { c => 2} will be deleted by perl, but %a won't be destroyed.
0
 

Author Comment

by:kushcu
ID: 11916251
I think my original posts weren't clear enough.

I'm writing this code in C (that's how I have HV*). I need C (or XS) code that uses Perl 5 API to do the copying. I need a deep copy of level 1, so non-recursive solutions would win over recursive ones.

Thanks.
0
 

Author Comment

by:kushcu
ID: 11923820
the XS code for Clon does what I want. didn't want to keep the question open.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Perl script to parse log and delete the file 17 172
Validating the data using Oracle DBD module. 5 65
Perl strange behaviour 5 69
Any syntax error for this clone.plscript 6 133
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now