Blame lib/diffseq.h

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