ENHANCED: faster format/3 when writing to binary streams
This is also more secure, since it does not change the atom table and therefore leaves little trace of what was processed.
This commit is contained in:
@@ -375,20 +375,9 @@ format(Fs, Args) :-
|
||||
format(Stream, Fs, Args) :-
|
||||
phrase(format_(Fs, Args), Cs),
|
||||
( stream_property(Stream, type(binary)) ->
|
||||
% maplist(char_code, Cs, Bytes) is currently a lot slower
|
||||
% than first converting Cs to an atom, and then to codes.
|
||||
% In the future, we can ideally avoid creating an atom here,
|
||||
% since an atom leaves traces in the system.
|
||||
atom_chars(A, Cs),
|
||||
atom_codes(A, Bytes),
|
||||
( member(NonByte, Bytes), NonByte > 255 ->
|
||||
char_code(Char, NonByte),
|
||||
throw(error(representation_error(Char), format/3))
|
||||
; true
|
||||
),
|
||||
% For binary streams, we use a specialised internal predicate
|
||||
% that uses only a single "write" operation for efficiency.
|
||||
'$put_bytes'(Stream, Bytes)
|
||||
'$put_bytes'(Stream, Cs)
|
||||
; maplist(put_char(Stream), Cs)
|
||||
).
|
||||
|
||||
|
||||
@@ -2022,8 +2022,24 @@ impl MachineState {
|
||||
let mut stream =
|
||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?;
|
||||
|
||||
let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2);
|
||||
let bytes = self.integers_to_bytevec(temp_v!(2), stub);
|
||||
let mut iter = self.heap_pstr_iter(self[temp_v!(2)]);
|
||||
let mut bytes = Vec::new();
|
||||
for c in iter.to_string().chars() {
|
||||
if c as u32 > 255 {
|
||||
|
||||
let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2);
|
||||
|
||||
let err = MachineError::type_error(
|
||||
self.heap.h(),
|
||||
ValidType::Byte,
|
||||
Addr::Char(c),
|
||||
);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
|
||||
bytes.push(c as u8);
|
||||
}
|
||||
|
||||
match stream.write(&bytes) {
|
||||
Ok(_) => {
|
||||
|
||||
Reference in New Issue
Block a user