fifo.scm
(module fifo mzscheme
	(provide fifo
		 fifo?
		 empty-fifo!
		 fifo-empty?
		 fifo+
		 fifo-)

;FIFO functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;=head1 FIFO
;;;
;;;This module gives an implementation of a thread safe
;;;First In First Out queue. It is based upon the
;;;L<SICP|http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec_3.3.2>
;;;implementation of a FIFO, but its setup is a littlebit different.
;;;Where the SICP implementation is based on a pair of pairs,
;;;this implementation uses a vector to get the same behaviour.
;;;The vector consists of a list and a pairs, where the pair points
;;;to the last element of the list. The rest of the vector elements
;;;represent semaphores. The first semaphore is used to implement
;;;a critical section. The second semaphore is used to implement
;;;a producer/consumer queue. The producer increases the semaphore
;;;for each new element in the queue. The consumer decreases the
;;;semaphore for each element taken from the queue. If the semaphore
;;;becomes 0, a consumer will block.
;;;
;;;=head2 Supportive macros
;;;
;;;These macros are not explained.
;;;
;;;=verbatim scm,8
(define-struct fifo-type (last-element lst sem depth)) 

(define-syntax last-fifo-element
  (syntax-rules ()
    ((_ fifo)
     (fifo-type-last-element fifo))))

(define-syntax last-fifo-element-set!
  (syntax-rules ()
    ((_ fifo item)
     (set-fifo-type-last-element! fifo item))))

(define-syntax fifo-list
  (syntax-rules ()
    ((_ fifo)
     (fifo-type-lst fifo))))

(define-syntax fifo-list-set!
  (syntax-rules ()
    ((_ fifo item)
     (set-fifo-type-lst! fifo item))))

(define-syntax protect
  (syntax-rules ()
    ((_ fifo body1 ...)
     (begin
       (semaphore-wait (fifo-type-sem fifo))
       (let ((result (begin
                       body1 ...)))
	 (semaphore-post (fifo-type-sem fifo))
         result)))))

(define-syntax inc-fifo-depth
  (syntax-rules ()
    ((_ fifo)
     (semaphore-post (fifo-type-depth fifo)))))

(define-syntax dec-fifo-depth
  (syntax-rules ()
    ((_ fifo)
     (semaphore-wait (fifo-type-depth fifo)))))
;;;=verbatim
;;;
;;;=head2 Interface
;;;
;;;=head3 C<(fifo-empty? fifo) : boolean>
;;;
;;;Returns #t, if fifo is empty, #f, otherwise.
;;;
;;;=verbatim scm,8
(define (fifo-empty? F)
  (null? (fifo-list F)))
;;;=verbatim
;;;
;;;=head3 C<(fifo+ fifo element) : fifo>
;;;
;;;Inserts a new element in the fifo. Returns fifo,
;;;but also alters the existing fifo.
;;;
;;;=verbatim scm,8
(define (fifo+ F element)
  (let ((item (cons element '())))
    (protect F
	     (inc-fifo-depth F)
	     (if (fifo-empty? F)
		 (begin
		   (fifo-list-set! F item)
		   (last-fifo-element-set! F item))
		 (begin
		   (set-cdr! (last-fifo-element F) item)
		   (last-fifo-element-set! F (cdr (last-fifo-element F))))))
    F))
;;;=verbatim
;;;
;;;=head3 C<(fifo- fifo) : scheme-object>
;;;
;;;Blocks if (fifo-empty?) is #t, until fifo+ is used
;;;to insert a new element. Takes an element from the
;;;fifo and returns it.
;;;
;;;=verbatim scm,8
(define (fifo- F)
  (dec-fifo-depth F)
  (protect F
	   (let ((element (car (fifo-list F))))
	     (fifo-list-set! F (cdr (fifo-list F)))
	     element)))
;;;=verbatim
;;;
;;;=head3 C<(fifo . elements) : fifo>
;;;
;;;Returns a new fifo, filled with all given arguments (elements).
;;;
;;;=verbatim scm,8
(define (fifo . elements)
  (let ((F (make-fifo-type (list) (list) (make-semaphore 1) (make-semaphore 0))))
  ;;;(let ((F (vector (list) (list) (make-semaphore 1) (make-semaphore 0) 'fifo)))
    (for-each
     (lambda (element)
       (fifo+ F element))
     elements)
    F))
;;;=verbatim
;;;
;;;=head3 C<(empty-fifo! fifo) : fifo>
;;;
;;;Empties fifo, i.e. removes all elements from fifo.
;;;This function actually creates a new fifo, and copies
;;;the vector elements to the existing fifo.
;;;
;;;=verbatim scm,8
(define (empty-fifo! F)
  (let ((F1 (fifo)))
    (last-fifo-element-set! F (last-fifo-element F1))
    (fifo-list-set! F (fifo-list F1))
    (set-fifo-type-sem! F (fifo-type-sem F1))
    (set-fifo-type-depth! F (fifo-type-depth F1))
    F))
;;;=verbatim
;;;
;;;=head3 C<(fifo? obj) : boolean>
;;;
;;;Determines if obj is a fifo. Returns #t if it does so,
;;;returns #f, otherwise. Note: All fifos are vectors.
;;;
;;;=verbatim scm,8
(define (fifo? F)
  (fifo-type? F))
;;;=verbatim
;;;
;;;=head2 Info
;;;
;;;S<C<Author(s):>> Hans Oesterholt-Dijkema (hansatelementalprogrammingdotorgextension).E<lb>
;;;S<C<Copyright:>> (c) 2005.E<lb>
;;;S<C<License  :>> L<Elemental Programming License|http://www.elemental-programming.org/epwiki/ep_license.html>.E<lb>
;;;S<C<File     :>> fifo.scm $Revision: 1.2 $
;;;
;;;=cut

)