This is the mail archive of the guile@sourceware.cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

patch for append


Hi!

Below is a patch for list.c which fixes the problem with circular lists
when given as parameters to append.

It also puts the documentation for append! at the proper place.

In this patch I decided to:
* keep the semantics (append) -> '(), although r4rs and r5rs are not
  explicit about whether this is allowed.
* assume that a rest argument is always a proper list.  I used SCM_NNULLP
  as the predicate to figure out whether the end of the list is not
  reached yet.  Alternatively, SCM_CONSP could have been used.  However,
  SCM_NNULLP can be assumed to be faster, since it does not have to check
  contents of the cell.  If we can assume that the argument is a proper
  list, both predicates lead to the same behaviour, but it is debatable
  whether both of them reflect the semantics in the same way.  Personally
  I feel a little better with SCM_CONSP, but still decided to use
  SCM_NNULLP, because the semantic difference is quite small and the
  performance of SCM_NNULLP can be expected to be quite some better.
  In case you feel bad about not typechecking the rest argument for being
  a proper list, I think the best solution would be as a compile time
  option, like defining DEBUG or something.

BTW:  I signed the copyright assignment for the FSF and will put it into
the post box this evening.

Best regards,
Dirk Herrmann


RCS file: /cvs/guile/guile/guile-core/libguile/list.c,v
retrieving revision 1.28
diff -u -p -r1.28 list.c
--- list.c	2000/01/18 13:09:54	1.28
+++ list.c	2000/01/18 15:58:45
@@ -181,41 +181,56 @@ SCM_DEFINE (scm_length, "length", 1, 0, 
 
 SCM_DEFINE (scm_append, "append", 0, 0, 1, 
             (SCM args),
-	    "A destructive version of @code{append} (@pxref{Pairs and Lists,,,r4rs,\n"
-	    "The Revised^4 Report on Scheme}).  The cdr field of each list's final\n"
-	    "pair is changed to point to the head of the next list, so no consing is\n"
-	    "performed.  Return a pointer to the mutated list.")
+	    "")
 #define FUNC_NAME s_scm_append
 {
+  SCM arg = SCM_EOL;
   SCM res = SCM_EOL;
-  SCM *lloc = &res, arg;
-  if (SCM_IMP(args)) {
-    SCM_VALIDATE_NULL (SCM_ARGn, args);
-    return res;
-  }
-  SCM_VALIDATE_CONS (SCM_ARGn, args);
-  while (1) {
-    arg = SCM_CAR(args);
-    args = SCM_CDR(args);
-    if (SCM_IMP(args)) {
-      *lloc = arg;
-      SCM_VALIDATE_NULL (SCM_ARGn, args);
-      return res;
-    }
-    SCM_VALIDATE_CONS (SCM_ARGn, args);
-    for (; SCM_CONSP(arg); arg = SCM_CDR(arg)) {
-      *lloc = scm_cons(SCM_CAR(arg), SCM_EOL);
-      lloc = SCM_CDRLOC(*lloc);
+  SCM *lloc = &res;
+
+  while (SCM_NNULLP (args)) 
+    {
+      arg = SCM_CAR (args);
+      args = SCM_CDR (args);
+      if (SCM_NNULLP (args)) 
+	{
+	  /* arg is not the last argument, thus it has to be copied */
+
+	  SCM tortoise = arg;
+	  SCM hare = arg;
+	  while (SCM_CONSP (hare))
+	    {
+	      *lloc = scm_cons(SCM_CAR (hare), SCM_EOL);
+	      lloc = SCM_CDRLOC (*lloc);
+	      hare = SCM_CDR (hare);
+	      if (SCM_CONSP (hare))
+		{
+		  *lloc = scm_cons(SCM_CAR (hare), SCM_EOL);
+		  lloc = SCM_CDRLOC (*lloc);
+		  hare = SCM_CDR (hare);
+
+		  tortoise = SCM_CDR (tortoise);
+		  if (hare == tortoise)
+		    {
+		      SCM_MISC_ERROR ("Circular structure: ~S", SCM_LIST1 (arg));
+		    }
+		}
+	    }
+	  SCM_VALIDATE_NULL (SCM_ARGn, hare);
+	}
     }
-    SCM_VALIDATE_NULL (SCM_ARGn, arg);
-  }
+  *lloc = arg;
+  return res;
 }
 #undef FUNC_NAME
 
 
 SCM_DEFINE (scm_append_x, "append!", 0, 0, 1, 
             (SCM args),
-"")
+	    "A destructive version of @code{append} (@pxref{Pairs and Lists,,,r4rs,\n"
+	    "The Revised^4 Report on Scheme}).  The cdr field of each list's final\n"
+	    "pair is changed to point to the head of the next list, so no consing is\n"
+	    "performed.  Return a pointer to the mutated list.")
 #define FUNC_NAME s_scm_append_x
 {
   SCM arg;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]