Blame lib/diffseq.h

Packit Service fdd496
/* Analyze differences between two vectors.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1988-1989, 1992-1995, 2001-2004, 2006-2017 Free Software
Packit Service fdd496
   Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation; either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* The basic idea is to consider two vectors as similar if, when
Packit Service fdd496
   transforming the first vector into the second vector through a
Packit Service fdd496
   sequence of edits (inserts and deletes of one element each),
Packit Service fdd496
   this sequence is short - or equivalently, if the ordered list
Packit Service fdd496
   of elements that are untouched by these edits is long.  For a
Packit Service fdd496
   good introduction to the subject, read about the "Levenshtein
Packit Service fdd496
   distance" in Wikipedia.
Packit Service fdd496
Packit Service fdd496
   The basic algorithm is described in:
Packit Service fdd496
   "An O(ND) Difference Algorithm and its Variations", Eugene W. Myers,
Packit Service fdd496
   Algorithmica Vol. 1, 1986, pp. 251-266,
Packit Service fdd496
   <http://dx.doi.org/10.1007/BF01840446>.
Packit Service fdd496
   See especially section 4.2, which describes the variation used below.
Packit Service fdd496
Packit Service fdd496
   The basic algorithm was independently discovered as described in:
Packit Service fdd496
   "Algorithms for Approximate String Matching", Esko Ukkonen,
Packit Service fdd496
   Information and Control Vol. 64, 1985, pp. 100-118,
Packit Service fdd496
   <http://dx.doi.org/10.1016/S0019-9958(85)80046-2>.
Packit Service fdd496
Packit Service fdd496
   Unless the 'find_minimal' flag is set, this code uses the TOO_EXPENSIVE
Packit Service fdd496
   heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N)
Packit Service fdd496
   at the price of producing suboptimal output for large inputs with
Packit Service fdd496
   many differences.  */
Packit Service fdd496
Packit Service fdd496
/* Before including this file, you need to define:
Packit Service fdd496
     ELEMENT                 The element type of the vectors being compared.
Packit Service fdd496
     EQUAL                   A two-argument macro that tests two elements for
Packit Service fdd496
                             equality.
Packit Service fdd496
     OFFSET                  A signed integer type sufficient to hold the
Packit Service fdd496
                             difference between two indices.  Usually
Packit Service fdd496
                             something like ptrdiff_t.
Packit Service fdd496
     EXTRA_CONTEXT_FIELDS    Declarations of fields for 'struct context'.
Packit Service fdd496
     NOTE_DELETE(ctxt, xoff) Record the removal of the object xvec[xoff].
Packit Service fdd496
     NOTE_INSERT(ctxt, yoff) Record the insertion of the object yvec[yoff].
Packit Service fdd496
     EARLY_ABORT(ctxt)       (Optional) A boolean expression that triggers an
Packit Service fdd496
                             early abort of the computation.
Packit Service fdd496
     USE_HEURISTIC           (Optional) Define if you want to support the
Packit Service fdd496
                             heuristic for large vectors.
Packit Service fdd496
   It is also possible to use this file with abstract arrays.  In this case,
Packit Service fdd496
   xvec and yvec are not represented in memory.  They only exist conceptually.
Packit Service fdd496
   In this case, the list of defines above is amended as follows:
Packit Service fdd496
     ELEMENT                 Undefined.
Packit Service fdd496
     EQUAL                   Undefined.
Packit Service fdd496
     XVECREF_YVECREF_EQUAL(ctxt, xoff, yoff)
Packit Service fdd496
                             A three-argument macro: References xvec[xoff] and
Packit Service fdd496
                             yvec[yoff] and tests these elements for equality.
Packit Service fdd496
   Before including this file, you also need to include:
Packit Service fdd496
     #include <limits.h>
Packit Service fdd496
     #include <stdbool.h>
Packit Service fdd496
     #include "minmax.h"
Packit Service fdd496
 */
Packit Service fdd496
Packit Service fdd496
/* Maximum value of type OFFSET.  */
Packit Service fdd496
#define OFFSET_MAX \
Packit Service fdd496
  ((((OFFSET)1 << (sizeof (OFFSET) * CHAR_BIT - 2)) - 1) * 2 + 1)
Packit Service fdd496
Packit Service fdd496
/* Default to no early abort.  */
Packit Service fdd496
#ifndef EARLY_ABORT
Packit Service fdd496
# define EARLY_ABORT(ctxt) false
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Use this to suppress gcc's "...may be used before initialized" warnings.
Packit Service fdd496
   Beware: The Code argument must not contain commas.  */
Packit Service fdd496
#ifndef IF_LINT
Packit Service fdd496
# if defined GCC_LINT || defined lint
Packit Service fdd496
#  define IF_LINT(Code) Code
Packit Service fdd496
# else
Packit Service fdd496
#  define IF_LINT(Code) /* empty */
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* As above, but when Code must contain one comma. */
Packit Service fdd496
#ifndef IF_LINT2
Packit Service fdd496
# if defined GCC_LINT || defined lint
Packit Service fdd496
#  define IF_LINT2(Code1, Code2) Code1, Code2
Packit Service fdd496
# else
Packit Service fdd496
#  define IF_LINT2(Code1, Code2) /* empty */
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/*
Packit Service fdd496
 * Context of comparison operation.
Packit Service fdd496
 */
Packit Service fdd496
struct context
Packit Service fdd496
{
Packit Service fdd496
  #ifdef ELEMENT
Packit Service fdd496
  /* Vectors being compared.  */
Packit Service fdd496
  ELEMENT const *xvec;
Packit Service fdd496
  ELEMENT const *yvec;
Packit Service fdd496
  #endif
Packit Service fdd496
Packit Service fdd496
  /* Extra fields.  */
Packit Service fdd496
  EXTRA_CONTEXT_FIELDS
Packit Service fdd496
Packit Service fdd496
  /* Vector, indexed by diagonal, containing 1 + the X coordinate of the point
Packit Service fdd496
     furthest along the given diagonal in the forward search of the edit
Packit Service fdd496
     matrix.  */
Packit Service fdd496
  OFFSET *fdiag;
Packit Service fdd496
Packit Service fdd496
  /* Vector, indexed by diagonal, containing the X coordinate of the point
Packit Service fdd496
     furthest along the given diagonal in the backward search of the edit
Packit Service fdd496
     matrix.  */
Packit Service fdd496
  OFFSET *bdiag;
Packit Service fdd496
Packit Service fdd496
  #ifdef USE_HEURISTIC
Packit Service fdd496
  /* This corresponds to the diff --speed-large-files flag.  With this
Packit Service fdd496
     heuristic, for vectors with a constant small density of changes,
Packit Service fdd496
     the algorithm is linear in the vector size.  */
Packit Service fdd496
  bool heuristic;
Packit Service fdd496
  #endif
Packit Service fdd496
Packit Service fdd496
  /* Edit scripts longer than this are too expensive to compute.  */
Packit Service fdd496
  OFFSET too_expensive;
Packit Service fdd496
Packit Service fdd496
  /* Snakes bigger than this are considered "big".  */
Packit Service fdd496
  #define SNAKE_LIMIT 20
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
struct partition
Packit Service fdd496
{
Packit Service fdd496
  /* Midpoints of this partition.  */
Packit Service fdd496
  OFFSET xmid;
Packit Service fdd496
  OFFSET ymid;
Packit Service fdd496
Packit Service fdd496
  /* True if low half will be analyzed minimally.  */
Packit Service fdd496
  bool lo_minimal;
Packit Service fdd496
Packit Service fdd496
  /* Likewise for high half.  */
Packit Service fdd496
  bool hi_minimal;
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Find the midpoint of the shortest edit script for a specified portion
Packit Service fdd496
   of the two vectors.
Packit Service fdd496
Packit Service fdd496
   Scan from the beginnings of the vectors, and simultaneously from the ends,
Packit Service fdd496
   doing a breadth-first search through the space of edit-sequence.
Packit Service fdd496
   When the two searches meet, we have found the midpoint of the shortest
Packit Service fdd496
   edit sequence.
Packit Service fdd496
Packit Service fdd496
   If FIND_MINIMAL is true, find the minimal edit script regardless of
Packit Service fdd496
   expense.  Otherwise, if the search is too expensive, use heuristics to
Packit Service fdd496
   stop the search and report a suboptimal answer.
Packit Service fdd496
Packit Service fdd496
   Set PART->(xmid,ymid) to the midpoint (XMID,YMID).  The diagonal number
Packit Service fdd496
   XMID - YMID equals the number of inserted elements minus the number
Packit Service fdd496
   of deleted elements (counting only elements before the midpoint).
Packit Service fdd496
Packit Service fdd496
   Set PART->lo_minimal to true iff the minimal edit script for the
Packit Service fdd496
   left half of the partition is known; similarly for PART->hi_minimal.
Packit Service fdd496
Packit Service fdd496
   This function assumes that the first elements of the specified portions
Packit Service fdd496
   of the two vectors do not match, and likewise that the last elements do not
Packit Service fdd496
   match.  The caller must trim matching elements from the beginning and end
Packit Service fdd496
   of the portions it is going to specify.
Packit Service fdd496
Packit Service fdd496
   If we return the "wrong" partitions, the worst this can do is cause
Packit Service fdd496
   suboptimal diff output.  It cannot cause incorrect diff output.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
diag (OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim, bool find_minimal,
Packit Service fdd496
      struct partition *part, struct context *ctxt)
Packit Service fdd496
{
Packit Service fdd496
  OFFSET *const fd = ctxt->fdiag;       /* Give the compiler a chance. */
Packit Service fdd496
  OFFSET *const bd = ctxt->bdiag;       /* Additional help for the compiler. */
Packit Service fdd496
#ifdef ELEMENT
Packit Service fdd496
  ELEMENT const *const xv = ctxt->xvec; /* Still more help for the compiler. */
Packit Service fdd496
  ELEMENT const *const yv = ctxt->yvec; /* And more and more . . . */
Packit Service fdd496
  #define XREF_YREF_EQUAL(x,y)  EQUAL (xv[x], yv[y])
Packit Service fdd496
#else
Packit Service fdd496
  #define XREF_YREF_EQUAL(x,y)  XVECREF_YVECREF_EQUAL (ctxt, x, y)
Packit Service fdd496
#endif
Packit Service fdd496
  const OFFSET dmin = xoff - ylim;      /* Minimum valid diagonal. */
Packit Service fdd496
  const OFFSET dmax = xlim - yoff;      /* Maximum valid diagonal. */
Packit Service fdd496
  const OFFSET fmid = xoff - yoff;      /* Center diagonal of top-down search. */
Packit Service fdd496
  const OFFSET bmid = xlim - ylim;      /* Center diagonal of bottom-up search. */
Packit Service fdd496
  OFFSET fmin = fmid;
Packit Service fdd496
  OFFSET fmax = fmid;           /* Limits of top-down search. */
Packit Service fdd496
  OFFSET bmin = bmid;
Packit Service fdd496
  OFFSET bmax = bmid;           /* Limits of bottom-up search. */
Packit Service fdd496
  OFFSET c;                     /* Cost. */
Packit Service fdd496
  bool odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd
Packit Service fdd496
                                   diagonal with respect to the northwest. */
Packit Service fdd496
Packit Service fdd496
  fd[fmid] = xoff;
Packit Service fdd496
  bd[bmid] = xlim;
Packit Service fdd496
Packit Service fdd496
  for (c = 1;; ++c)
Packit Service fdd496
    {
Packit Service fdd496
      OFFSET d;                 /* Active diagonal. */
Packit Service fdd496
      bool big_snake = false;
Packit Service fdd496
Packit Service fdd496
      /* Extend the top-down search by an edit step in each diagonal. */
Packit Service fdd496
      if (fmin > dmin)
Packit Service fdd496
        fd[--fmin - 1] = -1;
Packit Service fdd496
      else
Packit Service fdd496
        ++fmin;
Packit Service fdd496
      if (fmax < dmax)
Packit Service fdd496
        fd[++fmax + 1] = -1;
Packit Service fdd496
      else
Packit Service fdd496
        --fmax;
Packit Service fdd496
      for (d = fmax; d >= fmin; d -= 2)
Packit Service fdd496
        {
Packit Service fdd496
          OFFSET x;
Packit Service fdd496
          OFFSET y;
Packit Service fdd496
          OFFSET tlo = fd[d - 1];
Packit Service fdd496
          OFFSET thi = fd[d + 1];
Packit Service fdd496
          OFFSET x0 = tlo < thi ? thi : tlo + 1;
Packit Service fdd496
Packit Service fdd496
          for (x = x0, y = x0 - d;
Packit Service fdd496
               x < xlim && y < ylim && XREF_YREF_EQUAL (x, y);
Packit Service fdd496
               x++, y++)
Packit Service fdd496
            continue;
Packit Service fdd496
          if (x - x0 > SNAKE_LIMIT)
Packit Service fdd496
            big_snake = true;
Packit Service fdd496
          fd[d] = x;
Packit Service fdd496
          if (odd && bmin <= d && d <= bmax && bd[d] <= x)
Packit Service fdd496
            {
Packit Service fdd496
              part->xmid = x;
Packit Service fdd496
              part->ymid = y;
Packit Service fdd496
              part->lo_minimal = part->hi_minimal = true;
Packit Service fdd496
              return;
Packit Service fdd496
            }
Packit Service fdd496
        }
Packit Service fdd496
Packit Service fdd496
      /* Similarly extend the bottom-up search.  */
Packit Service fdd496
      if (bmin > dmin)
Packit Service fdd496
        bd[--bmin - 1] = OFFSET_MAX;
Packit Service fdd496
      else
Packit Service fdd496
        ++bmin;
Packit Service fdd496
      if (bmax < dmax)
Packit Service fdd496
        bd[++bmax + 1] = OFFSET_MAX;
Packit Service fdd496
      else
Packit Service fdd496
        --bmax;
Packit Service fdd496
      for (d = bmax; d >= bmin; d -= 2)
Packit Service fdd496
        {
Packit Service fdd496
          OFFSET x;
Packit Service fdd496
          OFFSET y;
Packit Service fdd496
          OFFSET tlo = bd[d - 1];
Packit Service fdd496
          OFFSET thi = bd[d + 1];
Packit Service fdd496
          OFFSET x0 = tlo < thi ? tlo : thi - 1;
Packit Service fdd496
Packit Service fdd496
          for (x = x0, y = x0 - d;
Packit Service fdd496
               xoff < x && yoff < y && XREF_YREF_EQUAL (x - 1, y - 1);
Packit Service fdd496
               x--, y--)
Packit Service fdd496
            continue;
Packit Service fdd496
          if (x0 - x > SNAKE_LIMIT)
Packit Service fdd496
            big_snake = true;
Packit Service fdd496
          bd[d] = x;
Packit Service fdd496
          if (!odd && fmin <= d && d <= fmax && x <= fd[d])
Packit Service fdd496
            {
Packit Service fdd496
              part->xmid = x;
Packit Service fdd496
              part->ymid = y;
Packit Service fdd496
              part->lo_minimal = part->hi_minimal = true;
Packit Service fdd496
              return;
Packit Service fdd496
            }
Packit Service fdd496
        }
Packit Service fdd496
Packit Service fdd496
      if (find_minimal)
Packit Service fdd496
        continue;
Packit Service fdd496
Packit Service fdd496
#ifdef USE_HEURISTIC
Packit Service fdd496
      /* Heuristic: check occasionally for a diagonal that has made lots
Packit Service fdd496
         of progress compared with the edit distance.  If we have any
Packit Service fdd496
         such, find the one that has made the most progress and return it
Packit Service fdd496
         as if it had succeeded.
Packit Service fdd496
Packit Service fdd496
         With this heuristic, for vectors with a constant small density
Packit Service fdd496
         of changes, the algorithm is linear in the vector size.  */
Packit Service fdd496
Packit Service fdd496
      if (200 < c && big_snake && ctxt->heuristic)
Packit Service fdd496
        {
Packit Service fdd496
          {
Packit Service fdd496
            OFFSET best = 0;
Packit Service fdd496
Packit Service fdd496
            for (d = fmax; d >= fmin; d -= 2)
Packit Service fdd496
              {
Packit Service fdd496
                OFFSET dd = d - fmid;
Packit Service fdd496
                OFFSET x = fd[d];
Packit Service fdd496
                OFFSET y = x - d;
Packit Service fdd496
                OFFSET v = (x - xoff) * 2 - dd;
Packit Service fdd496
Packit Service fdd496
                if (v > 12 * (c + (dd < 0 ? -dd : dd)))
Packit Service fdd496
                  {
Packit Service fdd496
                    if (v > best
Packit Service fdd496
                        && xoff + SNAKE_LIMIT <= x && x < xlim
Packit Service fdd496
                        && yoff + SNAKE_LIMIT <= y && y < ylim)
Packit Service fdd496
                      {
Packit Service fdd496
                        /* We have a good enough best diagonal; now insist
Packit Service fdd496
                           that it end with a significant snake.  */
Packit Service fdd496
                        int k;
Packit Service fdd496
Packit Service fdd496
                        for (k = 1; XREF_YREF_EQUAL (x - k, y - k); k++)
Packit Service fdd496
                          if (k == SNAKE_LIMIT)
Packit Service fdd496
                            {
Packit Service fdd496
                              best = v;
Packit Service fdd496
                              part->xmid = x;
Packit Service fdd496
                              part->ymid = y;
Packit Service fdd496
                              break;
Packit Service fdd496
                            }
Packit Service fdd496
                      }
Packit Service fdd496
                  }
Packit Service fdd496
              }
Packit Service fdd496
            if (best > 0)
Packit Service fdd496
              {
Packit Service fdd496
                part->lo_minimal = true;
Packit Service fdd496
                part->hi_minimal = false;
Packit Service fdd496
                return;
Packit Service fdd496
              }
Packit Service fdd496
          }
Packit Service fdd496
Packit Service fdd496
          {
Packit Service fdd496
            OFFSET best = 0;
Packit Service fdd496
Packit Service fdd496
            for (d = bmax; d >= bmin; d -= 2)
Packit Service fdd496
              {
Packit Service fdd496
                OFFSET dd = d - bmid;
Packit Service fdd496
                OFFSET x = bd[d];
Packit Service fdd496
                OFFSET y = x - d;
Packit Service fdd496
                OFFSET v = (xlim - x) * 2 + dd;
Packit Service fdd496
Packit Service fdd496
                if (v > 12 * (c + (dd < 0 ? -dd : dd)))
Packit Service fdd496
                  {
Packit Service fdd496
                    if (v > best
Packit Service fdd496
                        && xoff < x && x <= xlim - SNAKE_LIMIT
Packit Service fdd496
                        && yoff < y && y <= ylim - SNAKE_LIMIT)
Packit Service fdd496
                      {
Packit Service fdd496
                        /* We have a good enough best diagonal; now insist
Packit Service fdd496
                           that it end with a significant snake.  */
Packit Service fdd496
                        int k;
Packit Service fdd496
Packit Service fdd496
                        for (k = 0; XREF_YREF_EQUAL (x + k, y + k); k++)
Packit Service fdd496
                          if (k == SNAKE_LIMIT - 1)
Packit Service fdd496
                            {
Packit Service fdd496
                              best = v;
Packit Service fdd496
                              part->xmid = x;
Packit Service fdd496
                              part->ymid = y;
Packit Service fdd496
                              break;
Packit Service fdd496
                            }
Packit Service fdd496
                      }
Packit Service fdd496
                  }
Packit Service fdd496
              }
Packit Service fdd496
            if (best > 0)
Packit Service fdd496
              {
Packit Service fdd496
                part->lo_minimal = false;
Packit Service fdd496
                part->hi_minimal = true;
Packit Service fdd496
                return;
Packit Service fdd496
              }
Packit Service fdd496
          }
Packit Service fdd496
        }
Packit Service fdd496
#endif /* USE_HEURISTIC */
Packit Service fdd496
Packit Service fdd496
      /* Heuristic: if we've gone well beyond the call of duty, give up
Packit Service fdd496
         and report halfway between our best results so far.  */
Packit Service fdd496
      if (c >= ctxt->too_expensive)
Packit Service fdd496
        {
Packit Service fdd496
          OFFSET fxybest;
Packit Service fdd496
          OFFSET fxbest IF_LINT (= 0);
Packit Service fdd496
          OFFSET bxybest;
Packit Service fdd496
          OFFSET bxbest IF_LINT (= 0);
Packit Service fdd496
Packit Service fdd496
          /* Find forward diagonal that maximizes X + Y.  */
Packit Service fdd496
          fxybest = -1;
Packit Service fdd496
          for (d = fmax; d >= fmin; d -= 2)
Packit Service fdd496
            {
Packit Service fdd496
              OFFSET x = MIN (fd[d], xlim);
Packit Service fdd496
              OFFSET y = x - d;
Packit Service fdd496
              if (ylim < y)
Packit Service fdd496
                {
Packit Service fdd496
                  x = ylim + d;
Packit Service fdd496
                  y = ylim;
Packit Service fdd496
                }
Packit Service fdd496
              if (fxybest < x + y)
Packit Service fdd496
                {
Packit Service fdd496
                  fxybest = x + y;
Packit Service fdd496
                  fxbest = x;
Packit Service fdd496
                }
Packit Service fdd496
            }
Packit Service fdd496
Packit Service fdd496
          /* Find backward diagonal that minimizes X + Y.  */
Packit Service fdd496
          bxybest = OFFSET_MAX;
Packit Service fdd496
          for (d = bmax; d >= bmin; d -= 2)
Packit Service fdd496
            {
Packit Service fdd496
              OFFSET x = MAX (xoff, bd[d]);
Packit Service fdd496
              OFFSET y = x - d;
Packit Service fdd496
              if (y < yoff)
Packit Service fdd496
                {
Packit Service fdd496
                  x = yoff + d;
Packit Service fdd496
                  y = yoff;
Packit Service fdd496
                }
Packit Service fdd496
              if (x + y < bxybest)
Packit Service fdd496
                {
Packit Service fdd496
                  bxybest = x + y;
Packit Service fdd496
                  bxbest = x;
Packit Service fdd496
                }
Packit Service fdd496
            }
Packit Service fdd496
Packit Service fdd496
          /* Use the better of the two diagonals.  */
Packit Service fdd496
          if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
Packit Service fdd496
            {
Packit Service fdd496
              part->xmid = fxbest;
Packit Service fdd496
              part->ymid = fxybest - fxbest;
Packit Service fdd496
              part->lo_minimal = true;
Packit Service fdd496
              part->hi_minimal = false;
Packit Service fdd496
            }
Packit Service fdd496
          else
Packit Service fdd496
            {
Packit Service fdd496
              part->xmid = bxbest;
Packit Service fdd496
              part->ymid = bxybest - bxbest;
Packit Service fdd496
              part->lo_minimal = false;
Packit Service fdd496
              part->hi_minimal = true;
Packit Service fdd496
            }
Packit Service fdd496
          return;
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
  #undef XREF_YREF_EQUAL
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Compare in detail contiguous subsequences of the two vectors
Packit Service fdd496
   which are known, as a whole, to match each other.
Packit Service fdd496
Packit Service fdd496
   The subsequence of vector 0 is [XOFF, XLIM) and likewise for vector 1.
Packit Service fdd496
Packit Service fdd496
   Note that XLIM, YLIM are exclusive bounds.  All indices into the vectors
Packit Service fdd496
   are origin-0.
Packit Service fdd496
Packit Service fdd496
   If FIND_MINIMAL, find a minimal difference no matter how
Packit Service fdd496
   expensive it is.
Packit Service fdd496
Packit Service fdd496
   The results are recorded by invoking NOTE_DELETE and NOTE_INSERT.
Packit Service fdd496
Packit Service fdd496
   Return false if terminated normally, or true if terminated through early
Packit Service fdd496
   abort.  */
Packit Service fdd496
Packit Service fdd496
static bool
Packit Service fdd496
compareseq (OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim,
Packit Service fdd496
            bool find_minimal, struct context *ctxt)
Packit Service fdd496
{
Packit Service fdd496
#ifdef ELEMENT
Packit Service fdd496
  ELEMENT const *xv = ctxt->xvec; /* Help the compiler.  */
Packit Service fdd496
  ELEMENT const *yv = ctxt->yvec;
Packit Service fdd496
  #define XREF_YREF_EQUAL(x,y)  EQUAL (xv[x], yv[y])
Packit Service fdd496
#else
Packit Service fdd496
  #define XREF_YREF_EQUAL(x,y)  XVECREF_YVECREF_EQUAL (ctxt, x, y)
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  /* Slide down the bottom initial diagonal.  */
Packit Service fdd496
  while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xoff, yoff))
Packit Service fdd496
    {
Packit Service fdd496
      xoff++;
Packit Service fdd496
      yoff++;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Slide up the top initial diagonal. */
Packit Service fdd496
  while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xlim - 1, ylim - 1))
Packit Service fdd496
    {
Packit Service fdd496
      xlim--;
Packit Service fdd496
      ylim--;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Handle simple cases. */
Packit Service fdd496
  if (xoff == xlim)
Packit Service fdd496
    while (yoff < ylim)
Packit Service fdd496
      {
Packit Service fdd496
        NOTE_INSERT (ctxt, yoff);
Packit Service fdd496
        if (EARLY_ABORT (ctxt))
Packit Service fdd496
          return true;
Packit Service fdd496
        yoff++;
Packit Service fdd496
      }
Packit Service fdd496
  else if (yoff == ylim)
Packit Service fdd496
    while (xoff < xlim)
Packit Service fdd496
      {
Packit Service fdd496
        NOTE_DELETE (ctxt, xoff);
Packit Service fdd496
        if (EARLY_ABORT (ctxt))
Packit Service fdd496
          return true;
Packit Service fdd496
        xoff++;
Packit Service fdd496
      }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      struct partition part IF_LINT2 (= { .xmid = 0, .ymid = 0 });
Packit Service fdd496
Packit Service fdd496
      /* Find a point of correspondence in the middle of the vectors.  */
Packit Service fdd496
      diag (xoff, xlim, yoff, ylim, find_minimal, &part, ctxt);
Packit Service fdd496
Packit Service fdd496
      /* Use the partitions to split this problem into subproblems.  */
Packit Service fdd496
      if (compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal, ctxt))
Packit Service fdd496
        return true;
Packit Service fdd496
      if (compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal, ctxt))
Packit Service fdd496
        return true;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return false;
Packit Service fdd496
  #undef XREF_YREF_EQUAL
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#undef ELEMENT
Packit Service fdd496
#undef EQUAL
Packit Service fdd496
#undef OFFSET
Packit Service fdd496
#undef EXTRA_CONTEXT_FIELDS
Packit Service fdd496
#undef NOTE_DELETE
Packit Service fdd496
#undef NOTE_INSERT
Packit Service fdd496
#undef EARLY_ABORT
Packit Service fdd496
#undef USE_HEURISTIC
Packit Service fdd496
#undef XVECREF_YVECREF_EQUAL
Packit Service fdd496
#undef OFFSET_MAX