git.fiddlerwoaroof.com
Browse code

initial

fiddlerwoaroof authored on 13/06/2017 01:29:00
Showing 6 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+*.fasl
0 2
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+This is the stub README.txt for the "vector-update-stream" project.
0 2
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+;;;; package.lisp
2
+
3
+(defpackage :vector-update-stream
4
+  (:use :cl :trivial-gray-streams))
5
+
0 6
new file mode 100644
... ...
@@ -0,0 +1,129 @@
1
+(in-package :vector-update-stream)
2
+
3
+(defclass vector-update-stream (fundamental-binary-output-stream)
4
+  ((vector :accessor vector-stream-vector :initarg :vector))
5
+  (:documentation "A binary output stream that writes its data to an associated vector."))
6
+
7
+(deftype octet ()
8
+  '(unsigned-byte 8))
9
+
10
+(defun make-update-stream (array)
11
+  (unless (and (array-has-fill-pointer-p array)
12
+	       (adjustable-array-p array))
13
+    (error "GET-STREAM-FOR-ARRAY requires an adjustable array with a fill pointer"))
14
+  (make-instance 'vector-update-stream
15
+		 :vector array))
16
+
17
+(defun check-if-open (stream)
18
+  "Checks if STREAM is open and signals an error otherwise."
19
+  (unless (open-stream-p stream)
20
+    (error 'flexi-streams:in-memory-stream-closed-error
21
+	   :stream stream)))
22
+
23
+(defmethod stream-write-byte ((stream vector-update-stream) byte)
24
+  "Writes a byte \(octet) by extending the underlying vector."
25
+  (check-if-open stream)
26
+  (with-accessors ((vector vector-stream-vector)) stream
27
+    (let ((orig-fill-pointer (fill-pointer vector)))
28
+      (handler-bind ((error (lambda (c)
29
+			      (declare (ignore c))
30
+			      (setf (fill-pointer vector) orig-fill-pointer))))
31
+	(vector-push-extend byte vector)))))
32
+
33
+(defmethod stream-write-sequence ((stream vector-update-stream) sequence start end &key)
34
+  "Just calls VECTOR-PUSH-EXTEND repeatedly."
35
+  (declare (fixnum start end))
36
+  (with-accessors ((vector vector-stream-vector)) stream
37
+    (let ((orig-fill-pointer (fill-pointer vector)))
38
+      (handler-bind ((error (lambda (c)
39
+			      (declare (ignore c))
40
+			      (setf (fill-pointer vector) orig-fill-pointer))))
41
+	(loop for index of-type fixnum from start below end
42
+	   do (vector-push-extend (elt sequence index) vector))))
43
+    sequence))
44
+
45
+(defmethod stream-file-position ((stream vector-update-stream))
46
+  "Simply returns the fill pointer of the underlying vector."
47
+  (with-accessors ((vector vector-stream-vector)) stream
48
+    (fill-pointer vector)))
49
+
50
+(defmethod (setf stream-file-position) (position-spec (stream vector-update-stream))
51
+  "Sets the fill pointer underlying vector if POSITION-SPEC is
52
+acceptable.  Adjusts the vector if necessary."
53
+  (with-accessors ((vector vector-stream-vector))
54
+      stream
55
+    (let* ((total-size (array-total-size vector))
56
+           (new-fill-pointer
57
+            (case position-spec
58
+              (:start 0)
59
+              (:end
60
+               (warn "File position designator :END doesn't really make sense for an output stream.")
61
+               total-size)
62
+              (otherwise
63
+               (unless (integerp position-spec)
64
+                 (error 'flexi-streams:in-memory-stream-position-spec-error
65
+                        :format-control "Unknown file position designator: ~S."
66
+                        :format-arguments (list position-spec)
67
+                        :stream stream
68
+                        :position-spec position-spec))
69
+               (unless (<= 0 position-spec array-total-size-limit)
70
+                 (error 'flexi-streams:in-memory-stream-position-spec-error
71
+                        :format-control "File position designator ~S is out of bounds."
72
+                        :format-arguments (list position-spec)
73
+                        :stream stream
74
+                        :position-spec position-spec))
75
+               position-spec))))
76
+      (declare (fixnum total-size new-fill-pointer))
77
+      (when (> new-fill-pointer total-size)
78
+        (adjust-array vector new-fill-pointer))
79
+      (setf (fill-pointer vector) new-fill-pointer)
80
+      position-spec)))
81
+
82
+(defmethod get-output-stream-sequence ((stream vector-update-stream) &key)
83
+  "Returns a vector containing, in order, all the octets that have
84
+been output to the IN-MEMORY stream STREAM. This operation clears any
85
+octets on STREAM, so the vector contains only those octets which have
86
+been output since the last call to GET-OUTPUT-STREAM-SEQUENCE or since
87
+the creation of the stream, whichever occurred most recently.  If
88
+AS-LIST is true the return value is coerced to a list."
89
+  (vector-stream-vector stream))
90
+
91
+(defmacro deftest (name (expected actual-init) (&rest bindings) &body actions)
92
+  (alexandria:with-gensyms (assertion-template)
93
+    `(let* ((expected ,expected)
94
+	    (actual ,actual-init)
95
+	    ,@bindings
96
+	    (,assertion-template (formatter "~&~a Test: ~:[fail~%~4texpected ~s~%~4tactual ~s~;succeed~]~%")))
97
+       (declare (ignorable ,assertion-template))
98
+       (flet ((check (assertion)
99
+		    (funcall ,assertion-template t ',name (funcall assertion expected actual) expected actual)))
100
+	 ,@actions)
101
+       (values))))
102
+
103
+(defun test ()
104
+  (deftest write-sequence
105
+      (#(1 2 3) (make-array 0 :adjustable t :fill-pointer 0))
106
+      ((vs (make-update-stream actual)))
107
+    (write-sequence expected vs)
108
+    (check 'serapeum:vector=))
109
+
110
+  (deftest write-sequence-undo-on-error
111
+      (#(1 2 3) (make-array 0 :adjustable t :fill-pointer 0 :element-type 'octet))
112
+      ((vs (make-update-stream actual)))
113
+    (write-sequence expected vs)
114
+    (handler-case (write-sequence #(1 2 3 #\a) vs)
115
+      (type-error (c) c (values)))
116
+    (check 'serapeum:vector=))
117
+
118
+  (deftest write-byte
119
+      (#(1) (make-array 0 :adjustable t :fill-pointer 0))
120
+      ((vs (make-update-stream actual)))
121
+    (write-byte 1 vs)
122
+    (check 'serapeum:vector=))
123
+
124
+  (deftest write-byte-undo-on-error
125
+      (#() (make-array 0 :adjustable t :fill-pointer 0 :element-type 'octet))
126
+      ((vs (make-update-stream actual)))
127
+    (handler-case (stream-write-byte vs #\a)
128
+      (type-error (c) c (values)))
129
+    (check 'serapeum:vector=)))
0 130
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+;;;; vector-update-stream.asd
2
+
3
+(asdf:defsystem #:vector-update-stream
4
+  :description "A stream that updates a user-provided backing vector, based on flexi-streams"
5
+  :author "Ed Langley <fiddlerwoaroof@gmail.com"
6
+  :license "BSD-2-CLAUSE"
7
+  :depends-on (#:trivial-gray-streams
8
+	       #:flexi-streams
9
+               #:alexandria
10
+               #:serapeum)
11
+  :serial t
12
+  :components ((:file "package")
13
+               (:file "stream-to-vector")))
14
+
0 15
new file mode 100644
... ...
@@ -0,0 +1,6 @@
1
+;;;; vector-update-stream.lisp
2
+
3
+(in-package #:vector-update-stream)
4
+
5
+;;; "vector-update-stream" goes here. Hacks and glory await!
6
+