- (type fixnum start end))
- (let* ((string (if (typep string '(simple-array character (*)))
- string
- (coerce string '(simple-array character (*)))))
- (current (string-output-stream-index stream))
- (length (- end start))
- (dst-end (+ length current))
- (workspace (string-output-stream-string stream)))
- (declare (type (simple-array character (*)) workspace string)
- (type fixnum current length dst-end))
- (if (> dst-end (the fixnum (length workspace)))
- (let ((new-workspace (make-string (+ (* current 2) length))))
- (replace new-workspace workspace :end2 current)
- (replace new-workspace string
- :start1 current :end1 dst-end
- :start2 start :end2 end)
- (setf (string-output-stream-string stream) new-workspace))
- (replace workspace string
- :start1 current :end1 dst-end
- :start2 start :end2 end))
- (setf (string-output-stream-index stream) dst-end)))
+ (type index start end))
+ (let* ((full-length (- end start))
+ (length full-length)
+ (buffer (string-output-stream-buffer stream))
+ (pointer (string-output-stream-pointer stream))
+ (space (- (length buffer) pointer))
+ (here (min space length))
+ (stop (+ start here))
+ (overflow (- length space)))
+ (declare (index length space here stop full-length)
+ (fixnum overflow)
+ (type (simple-array character (*)) buffer))
+ (tagbody
+ :more
+ (when (plusp here)
+ (etypecase string
+ ((simple-array character (*))
+ (replace buffer string :start1 pointer :start2 start :end2 stop))
+ (simple-base-string
+ (replace buffer string :start1 pointer :start2 start :end2 stop))
+ ((simple-array nil (*))
+ (replace buffer string :start1 pointer :start2 start :end2 stop)))
+ (setf (string-output-stream-pointer stream) (+ here pointer)))
+ (when (plusp overflow)
+ (setf start stop
+ length (- end start)
+ buffer (string-output-stream-new-buffer
+ stream (max overflow (string-output-stream-index stream)))
+ pointer 0
+ space (length buffer)
+ here (min space length)
+ stop (+ start here)
+ ;; there may be more overflow if we used a buffer
+ ;; already allocated to the stream
+ overflow (- length space))
+ (go :more)))
+ (incf (string-output-stream-index stream) full-length)))
+
+;;; Factored out of the -misc method due to size.
+(defun set-string-output-stream-file-position (stream pos)
+ (let* ((index (string-output-stream-index stream))
+ (end (max index (string-output-stream-index-cache stream))))
+ (declare (index index end))
+ (setf (string-output-stream-index-cache stream) end)
+ (cond ((eq :start pos)
+ (loop while (string-output-stream-prev-buffer stream)))
+ ((eq :end pos)
+ (loop while (string-output-stream-next-buffer stream))
+ (let ((over (- (string-output-stream-index stream) end)))
+ (decf (string-output-stream-pointer stream) over))
+ (setf (string-output-stream-index stream) end))
+ ((< pos index)
+ (loop while (< pos index)
+ do (string-output-stream-prev-buffer stream)
+ (setf index (string-output-stream-index stream)))
+ (let ((step (- pos index)))
+ (incf (string-output-stream-pointer stream) step)
+ (setf (string-output-stream-index stream) pos)))
+ ((> pos index)
+ ;; We allow moving beyond the end of stream, implicitly
+ ;; extending the output stream.
+ (let ((next (string-output-stream-next-buffer stream)))
+ ;; Update after -next-buffer, INDEX is kept pointing at
+ ;; the end of the current buffer.
+ (setf index (string-output-stream-index stream))
+ (loop while (and next (> pos index))
+ do (setf next (string-output-stream-next-buffer stream)
+ index (string-output-stream-index stream))))
+ ;; Allocate new buffer if needed, or step back to
+ ;; the desired index and set pointer and index
+ ;; correctly.
+ (let ((diff (- pos index)))
+ (if (plusp diff)
+ (let* ((new (string-output-stream-new-buffer stream diff))
+ (size (length new)))
+ (aver (= pos (+ index size)))
+ (setf (string-output-stream-pointer stream) size
+ (string-output-stream-index stream) pos))
+ (let ((size (length (string-output-stream-buffer stream))))
+ (setf (string-output-stream-pointer stream) (+ size diff)
+ (string-output-stream-index stream) pos))))))))