diff --git a/loop.nw b/loop.nw index d2fa40b..ab5789b 100644 --- a/loop.nw +++ b/loop.nw @@ -903,6 +903,21 @@ time. %% TODO <>= (defun parse-article (v) + (let ((pos (search #(13 10 13 10) v))) + (if pos + (make-article + :headers (map 'string #'code-char (subseq v 0 pos)) + ;; Create a zero-copy window into the original byte array. + :body (make-array (- (length v) (+ pos 4)) + :element-type (array-element-type v) + :displaced-to v + :displaced-index-offset (+ pos 4))) + ;; What should we do if no body is found? Is that legal NNTP? + (make-article + :headers (map 'string #'code-char v) + :body (make-array 0 :element-type (array-element-type v)))))) + +(defun parse-article-old (v) (let ((parts (split-vector (vector 13 10 13 10) v nil :limit 2))) (make-article :headers (map 'string #'code-char (car parts)) :body (cadr parts)))) @@ -1784,10 +1799,27 @@ must have \verb|message-id|, \verb|subject|, \verb|from|, @ Sometimes we parse an article and sometimes we want to undo that -parsing. Am I doing something wrong? I wonder. +parsing. Am I doing something wrong? I wonder. We surely are, but +now is not the time for fixing this. <>= (defun unparse-article (parsed) + ;; 1. Build the new headers as a standard string + (let* ((headers-str (with-output-to-string (s) + (dolist (h (parse-headers (article-headers parsed))) + (format s "~a: ~a~c~c" (str:capitalize (car h)) (cdr h) #\return #\linefeed)) + ;; Add the final \r\n separating headers from the body + (format s "~c~c" #\return #\linefeed))) + ;; 2. Convert the string to a small byte array (~1 KB) + (headers-bytes (make-array (length headers-str) + :element-type '(unsigned-byte 8) + :initial-contents (map 'list #'char-code headers-str))) + ;; 3. Get the displaced, zero-copy body array + (body-bytes (article-body parsed))) + ;; 4. Let SBCL compile this into a fast C-level memcpy + (concatenate '(vector (unsigned-byte 8)) headers-bytes body-bytes))) + +(defun unparse-article-old (parsed) (data (let ((ls)) (dolist (h (parse-headers (article-headers parsed)))