stoe/core/containers.lisp

119 lines
3.3 KiB
Common Lisp

#|
This file is a part of stoe project.
Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr)
|#
(uiop:define-package :stoe/core/containers
(:use :cl :stoe/core/utils :stoe/core/thread)
(:export #:queue #:stack #:make-queue #:make-stack
#:enqueue #:dequeue #:push-stack #:pop-stack #:peek #:size
#:safe-queue #:safe-stack
#:make-safe-queue #:make-safe-stack))
(in-package :stoe/core/containers)
(defclass container ()
((data :initform nil))
(:documentation "A simple data container."))
(defclass queue (container)
()
(:documentation "A container acting like a queue."))
(defclass stack (container)
()
(:documentation "A container acting like a stack."))
(defgeneric enqueue (container elt)
(:documentation "Enqueue `elt' at the end of `queue'."))
(defgeneric dequeue (container)
(:documentation "Remove and return the first element of `queue'."))
(defgeneric push-stack (container elt)
(:documentation "Push `elt' at the front of `stack'."))
(defgeneric pop-stack (container)
(:documentation "Remove and return the element at the head of `stack'."))
(defgeneric peek (container)
(:documentation "Return the next element of `container' without removing it."))
(defun make-queue ()
"Make a queue instance."
(make-instance 'queue))
(defun make-stack ()
"Make a stack instance."
(make-instance 'stack))
(defmethod enqueue ((queue queue) elt)
(with-slots (data) queue
(setf data (append data (list elt)))))
(defmethod dequeue ((queue queue))
(with-slots (data) queue
(pop data)))
(defmethod push-stack ((stack stack) elt)
(with-slots (data) stack
(push elt data)))
(defmethod pop-stack ((stack stack))
(with-slots (data) stack
(pop data)))
(defmethod peek ((container container))
(with-slots (data) container
(first data)))
(defmethod size ((container container))
(with-slots (data) container
(length data)))
(defclass safe-container-mixin ()
((lock :initform (make-lock))
(waitp :initarg :waitp :accessor safe-container-wait-p))
(:documentation "A mixin for thread-safe containers."))
(defclass safe-queue (safe-container-mixin queue)
()
(:documentation "A thread-safe queue."))
(defclass safe-stack (safe-container-mixin stack)
()
(:documentation "A thread-safe stack."))
(defun make-safe-queue (&optional (waitp t))
"Make a safe-queue instance.
if `waitp', don't return until the mutex is released."
(make-instance 'safe-queue :waitp waitp))
(defun make-safe-stack (&optional (waitp t))
"Make a safe-stack instance.
if `waitp', don't return until the mutex is released."
(make-instance 'safe-stack :waitp waitp))
(defmethod enqueue :around ((queue safe-queue) elt)
(with-slots (lock waitp) queue
(with-lock-held (lock waitp)
(call-next-method))))
(defmethod dequeue :around ((queue safe-queue))
(with-slots (lock waitp) queue
(with-lock-held (lock waitp)
(call-next-method))))
(defmethod push-stack :around ((stack safe-stack) elt)
(with-slots (lock waitp) stack
(with-lock-held (lock waitp)
(call-next-method))))
(defmethod pop-stack :around ((stack safe-stack))
(with-slots (lock waitp) stack
(with-lock-held (lock waitp)
(call-next-method))))
(defmethod peek :around ((container safe-container-mixin))
(with-slots (lock waitp) container
(with-lock-held (lock waitp)
(call-next-method))))