will own the only reference to the new SV, and your code doesn't need to do
anything further to tidy up. Note that C<hv_store_ent> only reads the C<key>;
unlike C<val> it does not take ownership of it, so maintaining the correct
-reference count on C<key> is entirely the caller's responsibility. C<hv_store>
+reference count on C<key> is entirely the caller's responsibility. The reason
+it does not take ownership, is that C<key> is not used after this function
+returns, and so can be freed immediately. C<hv_store>
is not implemented as a call to C<hv_store_ent>, and does not create a temporary
SV for the key, so if your key data is not already in SV form then use
C<hv_store> in preference to C<hv_store_ent>.
/*
-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);
+ bool tied = SvRMAGICAL(hv) && (mg_find(MUTABLE_SV(hv), PERL_MAGIC_tied)
+#ifdef DYNAMIC_ENV_FETCH /* might not know number of keys yet */
+ || mg_find(MUTABLE_SV(hv), PERL_MAGIC_env)
+#endif
+ );
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 {
- SSize_t extend_size;
- /* 2*HvUSEDKEYS() should never be big enough to truncate or wrap */
- assert(HvUSEDKEYS(hv) <= (SSize_t_MAX >> 1));
- extend_size = (SSize_t)HvUSEDKEYS(hv) * 2;
- EXTEND(SP, extend_size);
+ Size_t nkeys = HvUSEDKEYS(hv);
+ SSize_t ext;
+
+ if (!nkeys)
+ return;
+
+ /* 2*nkeys() should never be big enough to truncate or wrap */
+ assert(nkeys <= (SSize_t_MAX >> 1));
+ ext = nkeys * ((flags == 3) ? 2 : 1);
+
+ EXTEND_MORTAL(nkeys);
+ EXTEND(SP, ext);
while ((entry = hv_iternext(hv))) {
- PUSHs(hv_iterkeysv(entry));
- 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));
}
}
sv_2mortal((SV *)gv)
);
}
- else if (klen == 3 && strEQs(key, "ISA") && GvAV(gv)) {
+ else if (memEQs(key, klen, "ISA") && GvAV(gv)) {
AV *isa = GvAV(gv);
MAGIC *mg = mg_find((SV*)isa, PERL_MAGIC_isa);
SV **svp, **end;
strip_magic:
svp = AvARRAY(isa);
- end = svp + AvFILLp(isa)+1;
+ end = svp + (AvFILLp(isa)+1);
while (svp < end) {
if (*svp)
mg_free_type(*svp, PERL_MAGIC_isaelem);
}
/*
-=for apidoc Am|HV *|hv_copy_hints_hv|HV *ohv
+=for apidoc hv_copy_hints_hv
A specialised version of L</newHVhv> for copying C<%^H>. C<ohv> must be
a pointer to a hash (which may have C<%^H> magic, but should be generally
}
/*
-=for apidoc m|HV *|refcounted_he_chain_2hv|const struct refcounted_he *c|U32 flags
+=for apidoc refcounted_he_chain_2hv
Generates and returns a C<HV *> representing the content of a
C<refcounted_he> chain.
}
/*
-=for apidoc m|SV *|refcounted_he_fetch_pvn|const struct refcounted_he *chain|const char *keypv|STRLEN keylen|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_pvn
Search along a C<refcounted_he> chain for an entry with the key specified
by C<keypv> and C<keylen>. If C<flags> has the C<REFCOUNTED_HE_KEY_UTF8>
}
/*
-=for apidoc m|SV *|refcounted_he_fetch_pv|const struct refcounted_he *chain|const char *key|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_pv
Like L</refcounted_he_fetch_pvn>, but takes a nul-terminated string
instead of a string/length pair.
}
/*
-=for apidoc m|SV *|refcounted_he_fetch_sv|const struct refcounted_he *chain|SV *key|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_sv
Like L</refcounted_he_fetch_pvn>, but takes a Perl scalar instead of a
string/length pair.
}
/*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_pvn|struct refcounted_he *parent|const char *keypv|STRLEN keylen|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_pvn
Creates a new C<refcounted_he>. This consists of a single key/value
pair and a reference to an existing C<refcounted_he> chain (which may
}
/*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_pv|struct refcounted_he *parent|const char *key|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_pv
Like L</refcounted_he_new_pvn>, but takes a nul-terminated string instead
of a string/length pair.
}
/*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_sv|struct refcounted_he *parent|SV *key|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_sv
Like L</refcounted_he_new_pvn>, but takes a Perl scalar instead of a
string/length pair.
}
/*
-=for apidoc m|void|refcounted_he_free|struct refcounted_he *he
+=for apidoc refcounted_he_free
Decrements the reference count of a C<refcounted_he> by one. If the
reference count reaches zero the structure's memory is freed, which
}
/*
-=for apidoc m|struct refcounted_he *|refcounted_he_inc|struct refcounted_he *he
+=for apidoc refcounted_he_inc
Increment the reference count of a C<refcounted_he>. The pointer to the
C<refcounted_he> is also returned. It is safe to pass a null pointer
/*
=for apidoc cop_fetch_label
-Returns the label attached to a cop.
-The flags pointer may be set to C<SVf_UTF8> or 0.
+Returns the label attached to a cop, and stores its length in bytes into
+C<*len>.
+Upon return, C<*flags> will be set to either C<SVf_UTF8> or 0.
+
+Alternatively, use the macro L</C<CopLABEL_len_flags>>;
+or if you don't need to know if the label is UTF-8 or not, the macro
+L</C<CopLABEL_len>>;
+or if you additionally dont need to know the length, L</C<CopLABEL>>.
=cut
*/
Save a label into a C<cop_hints_hash>.
You need to set flags to C<SVf_UTF8>
-for a UTF-8 label.
+for a UTF-8 label. Any other flag is ignored.
=cut
*/