-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmpsc-queue.lisp
56 lines (49 loc) · 1.66 KB
/
mpsc-queue.lisp
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))))