;;;; -*- mode:emacs-lisp;coding:utf-8 -*- ;;;;****************************************************************************** ;;;;FILE: pjb-queue.el ;;;;LANGUAGE: emacs lisp ;;;;SYSTEM: emacs ;;;;USER-INTERFACE: emacs ;;;;DESCRIPTION ;;;; ;;;; This module exports a queue type. This is a structure optimized for ;;;; FIFO operations, keeping a pointer to the head and the tail of a list. ;;;; ;;;;AUTHORS ;;;; Pascal J. Bourguignon ;;;;MODIFICATIONS ;;;; 2001-11-12 Creation. ;;;; 2001-12-31 Added pjb-queue-requeue. ;;;; Corrected the return value of some methods. ;;;;BUGS ;;;;LEGAL ;;;; LGPL ;;;; ;;;; Copyright Pascal J. Bourguignon 1990 - 2011 ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public ;;;; License as published by the Free Software Foundation; either ;;;; version 2 of the License, or (at your option) any later version. ;;;; ;;;; This library is distributed in the hope that it will be useful, ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;;; Lesser General Public License for more details. ;;;; ;;;; You should have received a copy of the GNU Lesser General Public ;;;; License along with this library; if not, write to the Free Software ;;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;;; ;;;;****************************************************************************** (provide 'pjb-queue) (require 'pjb-utilities) ;; import commented-out (defun pjb-queue-new () "DO: Creates a new pjb-queue. POST: (and (pjb-queue-p (pjb-queue-new)) (= 0 (pjb-queue-length queue))) RETURN: The new queue. NOTE: The structure of a pjb-queue is as follow: +------+------+ queue ----> | head | tail | +------+------+ | | V | 'pjb-queue +--+ | V +------+------+ | head | tail |--------------------------+ +------+------+ | | | V V +------+------+ +------+------+ +------+------+ | elem | next |--->| elem | next |--->| elem | next |--->nil +------+------+ +------+------+ +------+------+ | | | V V V +------+ +------+ +------+ | elem | | elem | | elem | +------+ +------+ +------+ " (cons 'pjb-queue (cons nil nil)) );;pjb-queue-new (defun pjb-queue-p (queue) "RETURN: Whether queue is a queue. DO: Checks that head points to a list whose last element is tail" (and (consp queue) (eq 'pjb-queue (car queue)) (let ( (head (cadr queue)) (tail (cddr queue)) ) (and (listp head) (listp tail) (or (and (null head) (null tail)) (and (not (null (cdr head))) (null (cdr tail))) (let ( (current head) ) (if (eq current tail) t ;; only one element (while (and (not (or (eq current head) (eq current tail)))) (setq current (cdr current))) (eq current tail))))))) );;pjb-queue-p (defun pjb-queue-length (queue) "PRE: (pjb-queue-p queue) RETURN: The number of elements in the queue." (if (not (eq 'pjb-queue (car queue))) (error "Parameter must be a queue.")) (length (cadr queue)) );;pjb-queue-length (defun pjb-queue-first-element (queue) "PRE: (pjb-queue-p queue) RETURN: The first element of the queue." (if (not (eq 'pjb-queue (car queue))) (error "Parameter must be a queue.")) (caar (cdr queue)) );;pjb-queue-first-element (defun pjb-queue-last-element (queue) "PRE: (pjb-queue-p queue) RETURN: The last element of the queue." (if (not (eq 'pjb-queue (car queue))) (error "Parameter must be a queue.")) (cadr (cdr queue)) );;pjb-queue-last-element (defun pjb-queue-enqueue (queue element) "PRE: (pjb-queue-p queue) l=(pjb-queue-length queue) POST: (eq (pjb-queue-last-element queue) element), (pjb-queue-p queue), l+1=(pjb-queue-length queue) RETURN: queue" (if (not (eq 'pjb-queue (car queue))) (error "Parameter must be a queue.")) (let ( (q (cdr queue)) ) ;; (car q) = head (cdr q) = tail (if (car q) (progn ;; There's already an element, just add to the tail. (setcdr (cdr q) (cons element nil)) (setcdr q (cddr q)) ) ;; The queue is empty, let's set the head. (setcar q (cons element nil)) (setcdr q (car q))) );;let queue );;pjb-queue-enqueue (defun pjb-queue-dequeue (queue) "PRE: (pjb-queue-p queue) l=(pjb-queue-length queue) f=(pjb-queue-first-element queue) POST: l>0 ==> l-1=(pjb-queue-length queue) l=0 ==> 0=(pjb-queue-length queue) RETURN: f" (let* ( (result (pjb-queue-first-element queue)) (q (cdr queue)) (second (cdar q)) ) (if second ;; remains at least one element. (setcar q second) ;; removing the last element, now queue is empty. (setcar q nil) (setcdr q nil)) result );;let );;pjb-queue-dequeue (defun pjb-queue-requeue (queue element) "DO: Insert the element at the beginning of the queue. PRE: (pjb-queue-p queue) l=(pjb-queue-length queue) POST: (eq (pjb-queue-first-element queue) element) (pjb-queue-p queue), l+1=(pjb-queue-length queue) RETURN: queue" (if (not (eq 'pjb-queue (car queue))) (error "Parameter must be a queue.")) (let ( (q (cdr queue)) ) (if (car q) ;; There's already an element, just insert before the head. (setcar q (cons element (car q))) ;; queue is empty, let's set the head. (setcar q (cons element nil)) (setcdr q (car q))) );;let queue );;pjb-queue-requeue; (defun pjb-queue-test () "DO: Test the queue data type. Insert test log at the point." (let (q (check (lambda (q) (insert (if (not (pjb-queue-p q)) (format " NOT A QUEUE !\n%S\n" q) (concat (format " Length=%2d\n" (pjb-queue-length q)) (if (< 0 (pjb-queue-length q)) (format " Head=%S\n Tail=%S\n" (pjb-queue-first-element q) (pjb-queue-last-element q)) "") (format " Queue=%S\n" q) )))) ) ) (insert "Creating a queue\n") (setq q (pjb-queue-new)) (funcall check q) (insert "Dequeuing empty queue\n") (insert (format "%S\n" (pjb-queue-dequeue q))) (funcall check q) (insert "Enqueuing...\n") (pjb-queue-enqueue q '(first)) (funcall check q) (insert "Enqueuing...\n") (pjb-queue-enqueue q '(second)) (funcall check q) (insert "Enqueuing...\n") (pjb-queue-enqueue q '(third)) (funcall check q) (insert "Enqueuing...\n") (pjb-queue-enqueue q '(fourth)) (funcall check q) (insert "Requeuing...\n") (pjb-queue-requeue q '(zeroeth)) (funcall check q) (while (< 0 (pjb-queue-length q)) (insert "Dequeuing queue\n") (insert (format "%S\n" (pjb-queue-dequeue q))) (funcall check q) ) (insert "Requeuing empty queue...\n") (pjb-queue-requeue q '(first)) (funcall check q) (insert "Requeuing...\n") (pjb-queue-requeue q '(second)) (funcall check q) (insert "Enqueuing...\n") (pjb-queue-enqueue q '(last)) (funcall check q) (while (< 0 (pjb-queue-length q)) (insert "Dequeuing queue\n") (insert (format "%S\n" (pjb-queue-dequeue q))) (funcall check q) ) ));;pjb-queue-test; ;;;; pjb-queue.el -- 2001-12-31 04:15:29 -- pascal ;;;;