diff options
author | David Mitchell <davem@iabyn.com> | 2017-07-21 14:32:57 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-07-27 11:30:24 +0100 |
commit | 8dc9003ff3914e78971f561eaece965e9ceeb49e (patch) | |
tree | 9ddb6c6946453365682c422f311a985fce2725ef /hv.c | |
parent | a16ac36c3b97d0d80762b2900667f3759f354d9f (diff) | |
download | perl-8dc9003ff3914e78971f561eaece965e9ceeb49e.tar.gz |
hv_pushkv(): handle keys() and values() too
The newish function hv_pushkv() currently just pushes all key/value pairs on
the stack. i.e. it does the equivalent of the perl code '() = %h'.
Extend it so that it can handle 'keys %h' and values %h' too.
This is basically moving the remaining list-context functionality out of
do_kv() and into hv_pushkv().
The rationale for this is that hv_pushkv() is a pure HV-related function,
while do_kv() is a pp function for several ops including OP_KEYS/VALUES,
and expects PL_op->op_flags/op_private to be valid.
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 51 |
1 files changed, 35 insertions, 16 deletions
@@ -969,47 +969,66 @@ Perl_hv_scalar(pTHX_ HV *hv) /* -Pushes all the keys and values of a hash onto the stack. +hv_pushkv(): push all the keys and/or values of a hash onto the stack. +The rough Perl equivalents: + () = %hash; + () = keys %hash; + () = values %hash; + Resets the hash's iterator. -The rough Perl equivalent: C< () = %hash; > -XXX this may at some point be extended to push 'keys %h' and 'values %h' -too. I might also unroll hv_iternext() - DAPM + +flags : 1 = push keys + 2 = push values + 1|2 = push keys and values + XXX use symbolic flag constants at some point? +I might unroll the non-tied hv_iternext() in here at some point - DAPM */ void -Perl_hv_pushkv(pTHX_ HV *hv) +Perl_hv_pushkv(pTHX_ HV *hv, U32 flags) { HE *entry; bool tied = SvRMAGICAL(hv) && mg_find(MUTABLE_SV(hv), PERL_MAGIC_tied); dSP; PERL_ARGS_ASSERT_HV_PUSHKV; + assert(flags); /* must be pushing at least one of keys and values */ (void)hv_iterinit(hv); if (tied) { + SSize_t ext = (flags == 3) ? 2 : 1; while ((entry = hv_iternext(hv))) { - EXTEND(SP, 2); - PUSHs(hv_iterkeysv(entry)); - PUSHs(hv_iterval(hv, entry)); + EXTEND(SP, ext); + if (flags & 1) + PUSHs(hv_iterkeysv(entry)); + if (flags & 2) + PUSHs(hv_iterval(hv, entry)); } } else { Size_t nkeys = HvUSEDKEYS(hv); - SSize_t nkv; + SSize_t ext; + + if (!nkeys) + return; + /* 2*nkeys() should never be big enough to truncate or wrap */ assert(nkeys <= (SSize_t_MAX >> 1)); - nkv = nkeys * 2; + ext = nkeys * ((flags == 3) ? 2 : 1); EXTEND_MORTAL(nkeys); - EXTEND(SP, nkv); + EXTEND(SP, ext); while ((entry = hv_iternext(hv))) { - SV *keysv = newSVhek(HeKEY_hek(entry)); - SvTEMP_on(keysv); - PL_tmps_stack[++PL_tmps_ix] = keysv; - PUSHs(keysv); - PUSHs(HeVAL(entry)); + if (flags & 1) { + SV *keysv = newSVhek(HeKEY_hek(entry)); + SvTEMP_on(keysv); + PL_tmps_stack[++PL_tmps_ix] = keysv; + PUSHs(keysv); + } + if (flags & 2) + PUSHs(HeVAL(entry)); } } |