+/* --- Stack manipulations ------------------------------------------------- */
+
+#ifndef SvCANEXISTDELETE
+# define SvCANEXISTDELETE(sv) \
+ (!SvRMAGICAL(sv) \
+ || ((mg = mg_find((SV *) sv, PERL_MAGIC_tied)) \
+ && (stash = SvSTASH(SvRV(SvTIED_obj((SV *) sv, mg)))) \
+ && gv_fetchmethod_autoload(stash, "EXISTS", TRUE) \
+ && gv_fetchmethod_autoload(stash, "DELETE", TRUE) \
+ ) \
+ )
+#endif
+
+/* ... Saving array elements ............................................... */
+
+STATIC I32 su_av_preeminent(pTHX_ AV *av, I32 key) {
+#define su_av_preeminent(A, K) su_av_preeminent(aTHX_ (A), (K))
+ MAGIC *mg;
+ HV *stash;
+
+ if (!av) return 0;
+ if (SvCANEXISTDELETE(av))
+ return av_exists(av, key);
+
+ return 1;
+}
+
+#ifndef SAVEADELETE
+
+typedef struct {
+ AV *av;
+ I32 key;
+} su_ud_adelete;
+
+STATIC void su_adelete(pTHX_ void *ud_) {
+ su_ud_adelete *ud = ud_;
+
+ av_delete(ud->av, ud->key, G_DISCARD);
+ SvREFCNT_dec(ud->av);
+
+ Safefree(ud);
+}
+
+STATIC void su_save_adelete(pTHX_ AV *av, I32 key) {
+#define su_save_adelete(A, K) su_save_adelete(aTHX_ (A), (K))
+ su_ud_adelete *ud;
+
+ Newx(ud, 1, su_ud_adelete);
+ ud->av = av;
+ ud->key = key;
+ SvREFCNT_inc(av);
+
+ SAVEDESTRUCTOR_X(su_adelete, ud);
+}
+
+#define SAVEADELETE(A, K) su_save_adelete((A), (K))
+
+#endif /* SAVEADELETE */
+
+STATIC void su_save_aelem(pTHX_ void *av_, SV *key, SV *val) {
+#define su_save_aelem(A, K, V) su_save_aelem(aTHX_ (A), (K), (V))
+ AV *av = av_;
+ I32 idx;
+ I32 preeminent;
+ SV **svp;
+
+ idx = SvIV(key);
+ preeminent = su_av_preeminent(av, idx);
+ svp = av_fetch(av, idx, 1);
+ if (!*svp || *svp == &PL_sv_undef) croak(PL_no_aelem, idx);
+
+ if (preeminent)
+ save_aelem(av, idx, svp);
+ else
+ SAVEADELETE(av, idx);
+
+ if (val) { /* local $x[$idx] = $val; */
+ SvSetMagicSV(*svp, val);
+ } else { /* local $x[$idx]; delete $x[$idx]; */
+ av_delete(av, idx, G_DISCARD);
+ }
+}
+
+/* ... Saving hash elements ................................................ */
+
+STATIC I32 su_hv_preeminent(pTHX_ HV *hv, SV *keysv) {
+#define su_hv_preeminent(H, K) su_hv_preeminent(aTHX_ (H), (K))
+ MAGIC *mg;
+ HV *stash;
+
+ if (!hv) return 0;
+ if (SvCANEXISTDELETE(hv) || mg_find((SV *) hv, PERL_MAGIC_env))
+ return hv_exists_ent(hv, keysv, 0);
+
+ return 1;
+}
+
+STATIC void su_save_helem(pTHX_ void *hv_, SV *keysv, SV *val) {
+#define su_save_helem(H, K, V) su_save_helem(aTHX_ (H), (K), (V))
+ HV *hv = hv_;
+ I32 preeminent;
+ HE *he;
+ SV **svp;
+
+ preeminent = su_hv_preeminent(hv, keysv);
+ he = hv_fetch_ent(hv, keysv, 1, 0);
+ svp = he ? &HeVAL(he) : NULL;
+ if (!svp || *svp == &PL_sv_undef) croak("Modification of non-creatable hash value attempted, subscript \"%s\"", SvPV_nolen_const(*svp));
+
+ if (HvNAME_get(hv) && isGV(*svp)) {
+ save_gp((GV *) *svp, 0);
+ return;
+ }
+
+ if (preeminent)
+ save_helem(hv, keysv, svp);
+ else {
+ STRLEN keylen;
+ const char * const key = SvPV_const(keysv, keylen);
+ SAVEDELETE(hv, savepvn(key, keylen),
+ SvUTF8(keysv) ? -(I32)keylen : (I32)keylen);
+ }
+
+ if (val) { /* local $x{$keysv} = $val; */
+ SvSetMagicSV(*svp, val);
+ } else { /* local $x{$keysv}; delete $x{$keysv}; */
+ hv_delete_ent(hv, keysv, G_DISCARD, HeHASH(he));
+ }
+}
+
+/* --- Actions ------------------------------------------------------------- */
+