#| 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 #: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))))