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:
Markus Triska
2020-06-14 10:06:27 +02:00
parent 005220b6d4
commit 409d3c168d
2 changed files with 19 additions and 14 deletions

View File

@@ -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)
).

View File

@@ -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(_) => {