diff options
Diffstat (limited to 'sys/plio/plupdate.x')
-rw-r--r-- | sys/plio/plupdate.x | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/sys/plio/plupdate.x b/sys/plio/plupdate.x new file mode 100644 index 00000000..bb90cc34 --- /dev/null +++ b/sys/plio/plupdate.x @@ -0,0 +1,158 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <mach.h> +include <plset.h> +include <plio.h> + +# PL_UPDATE -- Update the indicated line of a mask, i.e., insert a possibly +# modified line (encoded line list) into an image mask. This is where image +# compression in the Y direction occurs: if the line to be inserted is the +# "empty line", or a copy of the adjacent line earlier in the image, then we +# merely set the new line pointer to point to the line already stored, and +# increment the reference count for that line. When a new mask is created, +# all lines point to the "empty line" line list (PL_EMPTYLINE), which has a +# reference count equal to the number of lines in the mask. +# +# A new line may replace an existing line in storage if space permits and the +# reference count of the existing line is one or less, i.e., the stored line +# list is used only by the image line being updated. Otherwise the new line +# list will be appended to the line list buffer, which is resized to a larger +# size if it overflows. Note that the resize may move the buffer, which is +# why all line "pointers" are actually offsets into the line list buffer. +# +# We do not perform garbage collection on freed lines, rather we keep a count +# of the total amount of freed space (which cannot be reused), allowing the +# entire line list to be rebuilt periodically to reclaim the space, when the +# percentage of wasted space rises to a certain level. Since this can be a +# relatively expensive operation it is only performed by high level, more +# macroscopic operators, e.g., following a full mask rasterop, or before +# writing the mask to external storage. Note also that rebulding the mask +# may shift the stored line lists about, invalidating any line list pointers +# that may be cached in the calling procedure. This is another reason why +# we do not perform mask compression automatically if buffer overflow occurs +# during a line update. + +procedure pl_update (pl, v, ll) + +pointer pl #I mask descriptor +long v[PL_MAXDIM] #I coordinates of line in the mask +short ll[ARB] #I encoded line list + +pointer o_pp, n_pp +int totlen, axlen, index, i +int o_lp, n_lp, o_len, n_len, b_len + +bool pll_equal() +int pl_alloc() +errchk pl_alloc +define update_ 91 +define oob_ 92 + +begin + # Compute the index of the line in the line pointer array. + if (PL_NAXES(pl) == 2) { + # Optimized for case naxes=2. + index = v[2] + if (index < 1 || index > PL_AXLEN(pl,2)) + goto oob_ + } else { + # Generalized code. + index = 1 + totlen = 1 + do i = 2, PL_NAXES(pl) { + axlen = PL_AXLEN(pl,i) + if (v[i] < 1 || v[i] > axlen) + goto oob_ + index = index + totlen * (v[i] - 1) + totlen = totlen * axlen + } + } + + # Now the pointer to the current stored line list. + o_lp = PL_LP(pl,index) + o_pp = Ref (pl, o_lp) + if (o_pp == NULL) + return + + # Has the line been modified? + n_len = LL_LEN(ll) + if (n_len == LP_LEN(o_pp)) + if (pll_equal (ll, LL(pl,o_lp))) + return + + # Keep track of the number of edits. + PL_LLNUPDATES(pl) = PL_LLNUPDATES(pl) + 1 + + # Is the new line empty? + n_lp = PL_EMPTYLINE + n_pp = Ref (pl, n_lp) + if (n_len == LP_LEN(n_pp)) + if (pll_equal (ll, LL(pl,n_lp))) + goto update_ + + # Is the new line a copy of the adjacent line (Y=Y-1) in the image? + # Due to the short integer encoding a maximum of MAX_SHORT references + # are allowed per line. + + if (index > 1) { + n_lp = PL_LP(pl,index-1) + n_pp = Ref (pl, n_lp) + if (LP_NREF(n_pp) < MAX_SHORT) + if (n_len == LP_LEN(n_pp)) + if (pll_equal (ll, LL(pl,n_lp))) + goto update_ + } + + # The new line isn't a copy of the empty line or of an adjacent line, + # so copy it into the line list buffer. + + b_len = LP_BLEN(o_pp) + if (LP_NREF(o_pp) <= 1 && n_len <= b_len && o_lp != PL_EMPTYLINE) { + # Overwrite existing line. + + o_len = LP_LEN(o_pp) + call amovs (ll, LL(pl,o_lp), n_len) + LP_NREFS(o_pp) = 1 + LP_SETBLEN(o_pp, b_len) + PL_LLFREE(pl) = PL_LLFREE(pl) + (o_len - LP_LEN(o_pp)) + return + + } else { + # Add a new line. + + n_lp = pl_alloc (pl, n_len) + o_pp = Ref (pl, o_lp) + n_pp = Ref (pl, n_lp) + call amovs (ll, LL(pl,n_lp), n_len) + + LP_NREFS(n_pp) = 0 + LP_SETBLEN(n_pp, n_len) + PL_LLFREE(pl) = PL_LLFREE(pl) + n_len + } + + # We get here only if the new line has already been stored in the + # linelist buffer, with a pointer to such in N_LP, and a pointer to + # the old line in O_LP. Dereference the old line, which the new line + # is no longer associated with, and increase the reference count of + # the new line. +update_ + + # Dereference the old line and free the space if it is no longer used. + # If the old line buffer is freed we reclaim only LP_LEN words, since + # we already reclaimed LP_BLEN-LP_LEN in an earlier edit operation. + + LP_NREFS(o_pp) = LP_NREFS(o_pp) - 1 + if (LP_NREF(o_pp) == 0 && o_lp != PL_EMPTYLINE) + PL_LLFREE(pl) = PL_LLFREE(pl) + LP_LEN(o_pp) + + # Add another reference to the new line. + LP_NREFS(n_pp) = LP_NREFS(n_pp) + 1 + if (LP_NREF(n_pp) == 1 && n_lp != PL_EMPTYLINE) + PL_LLFREE(pl) = PL_LLFREE(pl) - LP_BLEN(n_pp) + + PL_LP(pl,index) = n_lp + return +oob_ + call syserr (SYS_PLREFOOB) +end |