summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2005-06-21 12:39:27 +0000
committerNicholas Clark <nick@ccl4.org>2005-06-21 12:39:27 +0000
commit6a76db8b55b6281740baab9e0ef221938c776ccd (patch)
tree8dd732447acb85bff372c5f27d33064684ca8f57 /sv.c
parent668825592272d9b757847b1a84b8de3cb1b3540b (diff)
downloadperl-6a76db8b55b6281740baab9e0ef221938c776ccd.tar.gz
Avoid having NULL entries in the weakref backreference array, and
make S_sv_add_backref O(1) (instead of O(n)) p4raw-id: //depot/perl@24924
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/sv.c b/sv.c
index b1cf433ee7..4cdfacc452 100644
--- a/sv.c
+++ b/sv.c
@@ -5230,13 +5230,6 @@ S_sv_add_backref(pTHX_ SV *tsv, SV *sv)
* by magic_killbackrefs() when tsv is being freed */
}
if (AvFILLp(av) >= AvMAX(av)) {
- I32 i;
- SV **svp = AvARRAY(av);
- for (i = AvFILLp(av); i >= 0; i--)
- if (!svp[i]) {
- svp[i] = sv; /* reuse the slot */
- return;
- }
av_extend(av, AvFILLp(av)+1);
}
AvARRAY(av)[++AvFILLp(av)] = sv; /* av_push() */
@@ -5258,8 +5251,23 @@ S_sv_del_backref(pTHX_ SV *sv)
Perl_croak(aTHX_ "panic: del_backref");
av = (AV *)mg->mg_obj;
svp = AvARRAY(av);
- for (i = AvFILLp(av); i >= 0; i--)
- if (svp[i] == sv) svp[i] = Nullsv;
+ /* We shouldn't be in here more than once, but for paranoia reasons lets
+ not assume this. */
+ for (i = AvFILLp(av); i >= 0; i--) {
+ if (svp[i] == sv) {
+ const SSize_t fill = AvFILLp(av);
+ if (i != fill) {
+ /* We weren't the last entry.
+ An unordered list has this property that you can take the
+ last element off the end to fill the hole, and it's still
+ an unordered list :-)
+ */
+ svp[i] = svp[fill];
+ }
+ svp[fill] = Nullsv;
+ AvFILLp(av) = fill - 1;
+ }
+ }
}
/*