;-*- Mode:     Lisp -*-
;;;; Author:   Paul Dietz
;;;; Created:  Mon Sep 23 20:59:10 2002
;;;; Contains: Aux. functions for testing REMOVE-DUPLICATES/DELETE-DUPLICATES

(in-package :cl-test)

(defun my-remove-duplicates (orig-sequence
			     &key from-end test test-not (start 0) end key)
  (assert (typep orig-sequence 'sequence))
  (let* ((sequence orig-sequence)
	 (len (length sequence)))
    (unless end (setq end len))
    (unless key (setq key #'identity))
    (cond
      (test (assert (not test-not)))
      (test-not (setq test #'(lambda (x y) (not (funcall test x y)))))
      (t (setq test #'eql)))
    (assert (integerp start))
    (assert (integerp end))
    (assert (<= 0 start end len))
    ;; (format t "start = ~A, end = ~A, len = ~A~%" start end len)
    (if from-end
	(psetq start (- len end)
	       end (- len start)
	       sequence (reverse sequence))
	(setq sequence (copy-seq sequence)))
    ;; (format t "start = ~A, end = ~A, len = ~A~%" start end len)
    (assert (<= 0 start end len) (start end len))
    (let ((result nil))
      (loop for i from 0 below start
	    do (push (elt sequence i) result))
      (loop for i from start below end
	    for x = (elt sequence i)
	    for kx = (if key (funcall key x) x)
	    unless (position kx
			     sequence
			     :start (1+ i)
			     :end end
			     :test test
			     :key key)
	    do (push x result))
      (loop for i from end below len
	    do (push (elt sequence i) result))
      (unless from-end (setq result (reverse result)))
      (cond
	((listp orig-sequence) result)
	((arrayp orig-sequence)
	 (make-array (length result) :initial-contents result
		     :element-type (array-element-type orig-sequence)))
	(t (assert nil))))))

(defun make-random-rdup-params (maxlen)
  "Make random input parameters for REMOVE-DUPLICATES."
  (multiple-value-bind (element-type type len start end from-end
				     count seq key test test-not)
      (make-random-rd-params maxlen)
    (declare (ignore count element-type))
    (let ((arg-list
	   (reduce #'nconc
		   (random-permute
		    (list
		     (when start (list :start start))
		     (cond (end (list :end end))
			   ((coin) (list :end nil)))
		     (cond (from-end (list :from-end from-end))
			   ((coin) (list :from-end nil)))
		     (cond (key (list :key key))
			   ;; ((coin) (list :key nil))
			   )
		     (when test (list :test test))
		     (when test-not (list :test test-not)))))))
      (values seq arg-list))))

(defun random-test-remove-dups (maxlen &optional (pure t))
  (multiple-value-bind (seq arg-list)
      (make-random-rdup-params maxlen)
    (let* ((seq1 (copy-seq seq))
	   (seq2 (copy-seq seq))
	   (seq1r (apply (if pure #'remove-duplicates
			   #'delete-duplicates)
			 seq1 arg-list))
	   (seq2r (apply #'my-remove-duplicates seq2 arg-list)))
      (cond
       ((and pure (not (equalp seq seq1))) :fail1)
       ((and pure (not (equalp seq seq2))) :fail2)
       ((not (equalp seq1r seq2r)) :fail3)
       (t t)))))
