-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmpsc-queue.lisp
More file actions
56 lines (49 loc) · 1.66 KB
/
mpsc-queue.lisp
File metadata and controls
56 lines (49 loc) · 1.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
(defpackage "MPSC-QUEUE"
(:use "CL" "SB-EXT")
(:shadow cl:get)
(:export "QUEUE" "P" "MAKE" "PUT" "GET" "P"))
(in-package "MPSC-QUEUE")
(defstruct (queue
(:constructor %make-queue (head)))
(head nil :type list)
(tail nil :type list))
(declaim (inline p))
(defun p (x)
(queue-p x))
(defun slow-get (queue)
(declare (type queue queue))
(let ((head (queue-head queue)))
(when head (return-from slow-get head)))
(let ((tail (loop ; stupid. It's just an xchg
(let ((tail (queue-tail queue)))
(when (eql (cas (queue-tail queue) tail nil)
tail)
(return tail))))))
(setf (queue-head queue) (reverse tail))))
(declaim (inline get put))
(defun get (queue &optional default)
(declare (type queue queue))
(let ((head (queue-head queue)))
(cond ((or head
(setf head (slow-get queue)))
(destructuring-bind (value . next) head
(setf (queue-head queue) next
(car head) nil
(cdr head) nil)
(values value t)))
(t
(values default nil)))))
(defun put (queue value)
(declare (type queue queue))
(let ((cons (list value)))
(loop
(let ((tail (queue-tail queue)))
(setf (cdr cons) tail)
(when (eql tail (cas (queue-tail queue) tail cons))
(return value))))))
(declaim (notinline get put))
(defun make (&optional initial-contents constructor &rest args)
(let ((contents (coerce initial-contents 'list)))
(if constructor
(apply constructor :head contents :tail nil args)
(%make-queue initial-contents))))