119 lines
3.3 KiB
Common 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))))
|