-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
string output stream? #47
Comments
What's missing? |
I don't want to create a new sequence. I want to write to an existing string with a fill pointer For example, I can (let ((string (make-array 0 :element-type 'character :adjustable t :fill-pointer t)))
(with-output-to-string (stream string)
(write-line "Hello, world!" stream))
string) #| => "Hello, world!" |# but there is no way for me to keep that stream alive as |
Ah, understood. I guess that you'll need to come up with a pull request to support that. |
Gotcha - I wanted to make sure such a thing didn't already exist without me knowing. I ended up doing the following: (defclass %string-output-stream (trivial-gray-streams:fundamental-character-output-stream)
((%string :initarg :string)))
(defmethod trivial-gray-streams:stream-write-char ((stream %string-output-stream) character)
(vector-push-extend character (slot-value stream '%string)))
(defmethod trivial-gray-streams:stream-write-string ((stream %string-output-stream) string &optional start end)
(let* ((%string (slot-value stream '%string))
(len (- (or end (length string)) (or start 0)))
(prev-len (fill-pointer %string))
(available-space (- (array-dimension %string 0) prev-len))
(new-len (+ prev-len len)))
(when (< available-space len)
(adjust-array %string new-len))
(setf (fill-pointer %string) new-len)
(replace %string string :start1 prev-len :start2 (or start 0) :end2 end))) which seems to work, but haven't confirmed if there's some missing part of the protocol I'm unaware about. Thanks |
@Zulu-Inuoe, the standard function is http://www.lispworks.com/documentation/lw50/CLHS/Body/f_mk_s_2.htm |
@avodonosov That does not allow me to write to an existing string |
@Zulu-Inuoe, ah, I see. Then it's even a kind of a defect in the standard, IMHO, beoause |
It actually can, by (defmacro my/with-output-to-string ((var str) &body body)
`(let ((,var (make-string-output-stream)))
,@body
(my/append-chars-to ,str (get-output-stream-string ,var)))) Which is, of course, inefficient, but has the same general behaviour (with the exception that it'll error "late" if the destination string is too small). But that's neither here nor there .. I ended up just writing my own class + specializations as noted above, but I still think this is a reasonable use-case if somebody is inspired to add to |
For the protocol, see the original Gray proposal: http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html, check at least the "Character output:" section. While most of the generic functions there are specified to have default methods, current CMUCL misses But simply returning NIL will deprive FORMAT ~T and FRESH-LINE of current column information, so they will work in the most dumb way. You may want to provide a real implementation of the Read the proposal for what else may be required, I am not used to implementing custom streams. In addition to the original proposal, consider 3 methods which are missing there In general, you may first write a test with as many CL output functions as possible (let ((stream (make-my-custom-string-stream ...)))
(write-char s ... )
(write-string s ... )
(write-sequence s ... )
(format s "~T..." ... )
(pprint s ... )
) and see if the results satisfy you. After all, your new class does not modify any existing behavior, it's purely additional feature, so it can be released in whatever form it is, and then fixed later, if any omissions are discovered. I am not a flexi-streams maintainer and not sure such a feature belongs to the flexi-streams scope; but that can also be a separate little library. |
Hey all,
One feature I tend to miss often is the ability to have a stream output to a string with a fill-pointer ala
with-output-to-string
, but with indefinite extent so I can keep it around.I see this is missing even from
flexi-streams
, with the same issue where you haveflexi-streams:with-output-to-sequence
, but no way tomake-output-to-sequence
.Any thoughts on an addition like that? I was going to write my own function making use of
flexi-streams::vector-output-stream
, as that's whatmake-in-memory-output-stream
uses, but I see that's not an exported symbol.The text was updated successfully, but these errors were encountered: