bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
* [PATCH] diffseq: new option NOTE_ORDERED
@ 2020-08-24 22:21 Paul Eggert
  2020-08-25 22:33 ` fstrcmp: Clarification regarding NOTE_ORDERED Bruno Haible
  0 siblings, 1 reply; 2+ messages in thread
From: Paul Eggert @ 2020-08-24 22:21 UTC (permalink / raw)
  To: bug-gnulib; +Cc: Paul Eggert

Problem reported by Phil Sainty <https://bugs.gnu.org/42931>.
* NEWS: Mention this.
* lib/diffseq.h (NOTE_ORDERED): New macro.
(IF_LINT2): Remove; no longer needed.
(compareseq): If (!NOTE_ORDERED), recurse on the smaller
subproblem and iterate to do the larger.
---
 ChangeLog     |  10 ++++
 NEWS          |   5 ++
 lib/diffseq.h | 128 +++++++++++++++++++++++++++++++++-----------------
 3 files changed, 99 insertions(+), 44 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c6b057e68..33cea278b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2020-08-24  Paul Eggert  <eggert@cs.ucla.edu>
+
+	diffseq: new option NOTE_ORDERED
+	Problem reported by Phil Sainty <https://bugs.gnu.org/42931>.
+	* NEWS: Mention this.
+	* lib/diffseq.h (NOTE_ORDERED): New macro.
+	(IF_LINT2): Remove; no longer needed.
+	(compareseq): If (!NOTE_ORDERED), recurse on the smaller
+	subproblem and iterate to do the larger.
+
 2020-08-23  Paul Eggert  <eggert@cs.ucla.edu>
 
 	sys_types: let Autoconf 2.70 do pid_t
diff --git a/NEWS b/NEWS
index ed88a7ea2..18465b260 100644
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,11 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2020-08-24  diffseq         If you do not define NOTE_ORDERED to true,
+                            the NOTE_DELETE and NOTE_INSERT actions might
+                            not be done in order, to help cut down worst-case
+                            recursion stack space from O(N) to O(log N).
+
 2020-08-01  libtextstyle-optional  You now need to invoke
                                    gl_LIBTEXTSTYLE_OPTIONAL explicitly, because
                                    this macro now takes an optional
diff --git a/lib/diffseq.h b/lib/diffseq.h
index c89363ac9..26e10bdd0 100644
--- a/lib/diffseq.h
+++ b/lib/diffseq.h
@@ -51,10 +51,14 @@
      EXTRA_CONTEXT_FIELDS    Declarations of fields for 'struct context'.
      NOTE_DELETE(ctxt, xoff) Record the removal of the object xvec[xoff].
      NOTE_INSERT(ctxt, yoff) Record the insertion of the object yvec[yoff].
+     NOTE_ORDERED            (Optional) A boolean expression saying that
+                             NOTE_DELETE and NOTE_INSERT calls must be
+                             issued in offset order.
      EARLY_ABORT(ctxt)       (Optional) A boolean expression that triggers an
                              early abort of the computation.
      USE_HEURISTIC           (Optional) Define if you want to support the
                              heuristic for large vectors.
+
    It is also possible to use this file with abstract arrays.  In this case,
    xvec and yvec are not represented in memory.  They only exist conceptually.
    In this case, the list of defines above is amended as follows:
@@ -63,6 +67,7 @@
      XVECREF_YVECREF_EQUAL(ctxt, xoff, yoff)
                              A three-argument macro: References xvec[xoff] and
                              yvec[yoff] and tests these elements for equality.
+
    Before including this file, you also need to include:
      #include <limits.h>
      #include <stdbool.h>
@@ -78,6 +83,10 @@
 # define EARLY_ABORT(ctxt) false
 #endif
 
+#ifndef NOTE_ORDERED
+# define NOTE_ORDERED false
+#endif
+
 /* Use this to suppress gcc's "...may be used before initialized" warnings.
    Beware: The Code argument must not contain commas.  */
 #ifndef IF_LINT
@@ -88,15 +97,6 @@
 # endif
 #endif
 
-/* As above, but when Code must contain one comma. */
-#ifndef IF_LINT2
-# if defined GCC_LINT || defined lint
-#  define IF_LINT2(Code1, Code2) Code1, Code2
-# else
-#  define IF_LINT2(Code1, Code2) /* empty */
-# endif
-#endif
-
 /*
  * Context of comparison operation.
  */
@@ -468,49 +468,89 @@ compareseq (OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim,
   #define XREF_YREF_EQUAL(x,y)  XVECREF_YVECREF_EQUAL (ctxt, x, y)
 #endif
 
-  /* Slide down the bottom initial diagonal.  */
-  while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xoff, yoff))
+  while (true)
     {
-      xoff++;
-      yoff++;
-    }
+      /* Slide down the bottom initial diagonal.  */
+      while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xoff, yoff))
+        {
+          xoff++;
+          yoff++;
+        }
 
-  /* Slide up the top initial diagonal. */
-  while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xlim - 1, ylim - 1))
-    {
-      xlim--;
-      ylim--;
-    }
+      /* Slide up the top initial diagonal. */
+      while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xlim - 1, ylim - 1))
+        {
+          xlim--;
+          ylim--;
+        }
 
-  /* Handle simple cases. */
-  if (xoff == xlim)
-    while (yoff < ylim)
-      {
-        NOTE_INSERT (ctxt, yoff);
-        if (EARLY_ABORT (ctxt))
-          return true;
-        yoff++;
-      }
-  else if (yoff == ylim)
-    while (xoff < xlim)
-      {
-        NOTE_DELETE (ctxt, xoff);
-        if (EARLY_ABORT (ctxt))
-          return true;
-        xoff++;
-      }
-  else
-    {
-      struct partition part IF_LINT2 (= { .xmid = 0, .ymid = 0 });
+      /* Handle simple cases. */
+      if (xoff == xlim)
+        {
+          while (yoff < ylim)
+            {
+              NOTE_INSERT (ctxt, yoff);
+              if (EARLY_ABORT (ctxt))
+                return true;
+              yoff++;
+            }
+          break;
+        }
+      if (yoff == ylim)
+        {
+          while (xoff < xlim)
+            {
+              NOTE_DELETE (ctxt, xoff);
+              if (EARLY_ABORT (ctxt))
+                return true;
+              xoff++;
+            }
+          break;
+        }
+
+      struct partition part;
 
       /* Find a point of correspondence in the middle of the vectors.  */
       diag (xoff, xlim, yoff, ylim, find_minimal, &part, ctxt);
 
       /* Use the partitions to split this problem into subproblems.  */
-      if (compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal, ctxt))
-        return true;
-      if (compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal, ctxt))
-        return true;
+      OFFSET xoff1, xlim1, yoff1, ylim1, xoff2, xlim2, yoff2, ylim2;
+      bool find_minimal1, find_minimal2;
+      if (!NOTE_ORDERED
+          && ((xlim + ylim) - (part.xmid + part.ymid)
+              < (part.xmid + part.ymid) - (xoff + yoff)))
+        {
+          /* The second problem is smaller and the caller doesn't
+             care about order, so do the second problem first to
+             lessen recursion.  */
+          xoff1 = part.xmid; xlim1 = xlim;
+          yoff1 = part.ymid; ylim1 = ylim;
+          find_minimal1 = part.hi_minimal;
+
+          xoff2 = xoff; xlim2 = part.xmid;
+          yoff2 = yoff; ylim2 = part.ymid;
+          find_minimal2 = part.lo_minimal;
+        }
+      else
+        {
+          xoff1 = xoff; xlim1 = part.xmid;
+          yoff1 = yoff; ylim1 = part.ymid;
+          find_minimal1 = part.lo_minimal;
+
+          xoff2 = part.xmid; xlim2 = xlim;
+          yoff2 = part.ymid; ylim2 = ylim;
+          find_minimal2 = part.hi_minimal;
+        }
+
+      /* Recurse to do one subproblem.  */
+      bool early = compareseq (xoff1, xlim1, yoff1, ylim1, find_minimal1, ctxt);
+      if (early)
+        return early;
+
+      /* Iterate to do the other subproblem.  */
+      xoff = xoff2; xlim = xlim2;
+      yoff = yoff2; ylim = ylim2;
+      find_minimal = find_minimal2;
     }
 
   return false;
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: fstrcmp: Clarification regarding NOTE_ORDERED
  2020-08-24 22:21 [PATCH] diffseq: new option NOTE_ORDERED Paul Eggert
@ 2020-08-25 22:33 ` Bruno Haible
  0 siblings, 0 replies; 2+ messages in thread
From: Bruno Haible @ 2020-08-25 22:33 UTC (permalink / raw)
  To: bug-gnulib; +Cc: Paul Eggert

> +     NOTE_ORDERED            (Optional) A boolean expression saying that
> +                             NOTE_DELETE and NOTE_INSERT calls must be
> +                             issued in offset order.

This patch makes it clear that NOTE_ORDERED == false is OK in the 'fstrcmp'
module.


2020-08-25  Bruno Haible  <bruno@clisp.org>

	fstrcmp: Clarification regarding NOTE_ORDERED.
	* lib/fstrcmp.c (NOTE_ORDERED): Define to false.

diff --git a/lib/fstrcmp.c b/lib/fstrcmp.c
index 1a4fbfd..49ce27a 100644
--- a/lib/fstrcmp.c
+++ b/lib/fstrcmp.c
@@ -46,6 +46,7 @@
   ptrdiff_t edit_count;
 #define NOTE_DELETE(ctxt, xoff) ctxt->edit_count++
 #define NOTE_INSERT(ctxt, yoff) ctxt->edit_count++
+#define NOTE_ORDERED false
 #define EARLY_ABORT(ctxt) ctxt->edit_count > 0
 /* We don't need USE_HEURISTIC, since it is unlikely in typical uses of
    fstrcmp().  */



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-08-25 22:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-24 22:21 [PATCH] diffseq: new option NOTE_ORDERED Paul Eggert
2020-08-25 22:33 ` fstrcmp: Clarification regarding NOTE_ORDERED Bruno Haible

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).