;;; -*- mode: lisp -*-
;;; $Id: lists.poplisp,v 1.0 2002/05/03 12:23:00 dada Exp $
(defparameter *SIZE* 10000)
(declaim (fixnum *SIZE*) (inline xcons push-queue))
(defvar *free-conses*)
(defun xcons (A B)
(let ((x *free-conses*))
(if x (progn (setf *free-conses* (cdr x) (car x) A (cdr x) B) x) (cons A B))))
(defmacro xpop (X)
`(prog1 (car ,x) (psetf ,x (cdr ,x) (cdr ,x) *free-conses* *free-conses* ,x)))
(defun push-queue (item queue &aux (new (xcons item nil)))
(if (cdr queue) (setf (cddr queue) new) (setf (car queue) new))
(setf (cdr queue) new)
(car queue))
(defmacro with-collector ((name) &body body)
(let ((collector (gensym)))
`(let ((,collector (xcons nil nil)))
(flet ((,name (value) (push-queue value ,collector)))
,@body
(car ,collector)))))
(defun test-list ()
(let* ((L1 (with-collector (conc) (loop for x fixnum from 1 to *SIZE* do (conc x))))
(L2 (with-collector (conc) (loop for x in L1 do (conc x))))
(L3 nil))
;; Move items from left of L2 to right of L3 (preserve order)
(setf L3 (with-collector (conc) (loop while L2 do (conc (xpop L2)))))
;; Move from tail of L3 to tail of L2 (reversing list)
;; start by reversing L3 so we can pop from the front
(setf L3 (nreverse L3))
(setf L2 (with-collector (conc) (loop while L3 do (conc (xpop L3)))))
;; Reverse L1 in place
(setf L1 (nreverse L1))
;; Check that (first L1) == *SIZE*
(assert (= (the fixnum (first L1)) *SIZE*))
;; Compare L1 and L2 for equality
(assert (equal L1 L2))
;; Return the length -- and return the conses to the free list
(prog1 (length (the list L1))
(setf *free-conses* (nconc *free-conses* L3 L2 L1)))))
(let ((n (parse-integer (or (car pop11::poparglist) "1")))
(num 0) (*free-conses* nil))
(loop repeat n fixnum do (setf num (test-list)))
(format t "~D~%" num))