# New Ticket Created by Jarrod # Please include the string: [perl #77066] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=77066 >
The current !STORE method on Hash does not make a copy of the given args to store, so it gobbles up any values in the top-level container passed to it (my %h = @a will empty @a, for example). This patch fixes that, and also offers a substantial performance increase by directly accessing the class's $!storage attribute. I should point out there's a fair bit of duplicate code in this patch making it a lot longer than it should be, but trying to reduce the duplicate code requires either the use of unnecessary loops or the use of parrot subs, which I wanted to avoid. Also, there's a lot of perl6scalar creation here and I'm not sure if it's all needed (do keys need to be put in new scalars? are they ever changed?)
diff --git a/src/core/Hash.pm b/src/core/Hash.pm index 23d3847..c3d2804 100644 --- a/src/core/Hash.pm +++ b/src/core/Hash.pm @@ -14,29 +14,93 @@ role Hash is EnumMap { done: } } - method !STORE(\$to_store) { + Q:PIR { + .local pmc self, to_store, items, storage + self = find_lex 'self' + to_store = find_lex '$to_store' + # We create a new storage hash, in case we are referenced in # what is being stored. - pir::setattribute__vPsP(self, '$!storage', pir::new__Ps('Hash')); + storage = root_new ['parrot';'Hash'] + setattribute self, '$!storage', storage - my $items = $to_store.flat; - while $items { - given $items.shift { - when Enum { - self{.key} = .value; - } - when EnumMap { - for $_.list { self{.key} = .value } - } - default { - die('Odd number of elements found where hash expected') - unless $items; - self{$_} = $items.shift; - } - } + # Sequencify args + $P0 = get_hll_global 'Seq' + items = $P0.'new'(to_store) + + #Get enum and enummap objects to call ACCEPTS on + .local pmc Enum, EnumMap + get_hll_global Enum, "Enum" + get_hll_global EnumMap, "EnumMap" + + .local pmc item + fill_loop: + unless items goto done + item = items.'shift'() + + $P0 = Enum.'ACCEPTS'(item) + unless $P0 goto check_emap + + $P1 = getattribute item, '$!key' + $P2 = getattribute item, '$!value' + $P1 = descalarref $P1 + $P2 = descalarref $P2 + $P1 = new ['Perl6Scalar'], $P1 + $P2 = new ['Perl6Scalar'], $P2 + setprop $P1, "scalar", true + setprop $P1, "rw", true + setprop $P2, "scalar", true + setprop $P2, "rw", true + + storage[$P1] = $P2 + goto fill_loop + + check_emap: + $P0 = EnumMap.'ACCEPTS'(item) + unless $P0 goto default + item = item.'list'() + copy_map_loop: + unless item goto fill_loop + $P0 = item.'shift'() + + $P1 = getattribute $P0, '$!key' + $P2 = getattribute $P0, '$!value' + $P1 = descalarref $P1 + $P2 = descalarref $P2 + $P1 = new ['Perl6Scalar'], $P1 + $P2 = new ['Perl6Scalar'], $P2 + setprop $P1, "scalar", true + setprop $P1, "rw", true + setprop $P2, "scalar", true + setprop $P2, "rw", true + + storage[$P1] = $P2 + goto copy_map_loop + + default: + unless items goto die_odd + $P0 = items.'shift'() + + $P1 = new ['Perl6Scalar'], item + $P2 = new ['Perl6Scalar'], $P0 + setprop $P1, "scalar", true + setprop $P1, "rw", true + setprop $P2, "scalar", true + setprop $P2, "rw", true + + storage[$P1] = $P2 + goto fill_loop + + die_odd: + $P1 = new "Str" + $P1 = 'Odd number of elements found where hash expected' + '&die'($P1) + + done: + %r = self } - self } method Bool() {