ENHANCED: much faster format/3 for text streams

This is now also used by format/2 to emit output on the terminal,
and significantly speeds up toplevel output of long strings.
This commit is contained in:
Markus Triska
2020-06-16 21:13:03 +02:00
parent d3563c30e7
commit 8958ea036e
3 changed files with 66 additions and 63 deletions

View File

@@ -229,8 +229,8 @@ pub enum SystemClauseType {
PeekCode,
PointsToContinuationResetMarker,
PutByte,
PutBytes,
PutChar,
PutChars,
PutCode,
REPL(REPLCodePtr),
ReadQueryTerm,
@@ -419,12 +419,12 @@ impl SystemClauseType {
&SystemClauseType::PutByte => {
clause_name!("$put_byte")
}
&SystemClauseType::PutBytes => {
clause_name!("$put_bytes")
}
&SystemClauseType::PutChar => {
clause_name!("$put_char")
}
&SystemClauseType::PutChars => {
clause_name!("$put_chars")
}
&SystemClauseType::PutCode => {
clause_name!("$put_code")
}
@@ -560,12 +560,12 @@ impl SystemClauseType {
("$put_byte", 2) => {
Some(SystemClauseType::PutByte)
}
("$put_bytes", 2) => {
Some(SystemClauseType::PutBytes)
}
("$put_char", 2) => {
Some(SystemClauseType::PutChar)
}
("$put_chars", 2) => {
Some(SystemClauseType::PutChars)
}
("$put_code", 2) => {
Some(SystemClauseType::PutCode)
}

View File

@@ -3,7 +3,7 @@
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
formatted strings. format/2 is provided for impure output.
formatted strings. format/[2,3] are provided for impure output.
Usage:
======
@@ -369,17 +369,15 @@ digits(uppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
format(Fs, Args) :-
phrase(format_(Fs, Args), Cs),
maplist(write, Cs).
current_output(Stream),
format(Stream, Fs, Args).
format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) ->
% For binary streams, we use a specialised internal predicate
% that uses only a single "write" operation for efficiency.
'$put_bytes'(Stream, Cs)
; maplist(put_char(Stream), Cs)
).
% we use a specialised internal predicate that uses only a
% single "write" operation for efficiency. It is equivalent to
% maplist(put_char(Stream), Cs). It also works for binary streams.
'$put_chars'(Stream, Cs).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs).

View File

@@ -1928,6 +1928,58 @@ impl MachineState {
}
}
}
&SystemClauseType::PutChars => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_chars", 2)?;
let mut bytes = Vec::new();
let string = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
if stream.options.stream_type == StreamType::Binary {
for c in string.chars() {
if c as u32 > 255 {
let stub = MachineError::functor_stub(clause_name!("$put_chars"), 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);
}
} else {
bytes = string.into_bytes();
}
match stream.write(&bytes) {
Ok(_) => {
return return_from_clause!(self.last_call, self);
}
_ => {
let stub = MachineError::functor_stub(
clause_name!("$put_chars"),
2,
);
let addr = self.heap.to_unifiable(
HeapCellValue::Stream(stream.clone()),
);
return Err(self.error_form(
MachineError::existence_error(
self.heap.h(),
ExistenceError::Stream(addr),
),
stub,
));
}
}
}
&SystemClauseType::PutByte => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "put_byte", 2)?;
@@ -2018,53 +2070,6 @@ impl MachineState {
}
}
}
&SystemClauseType::PutBytes => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?;
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(_) => {
return return_from_clause!(self.last_call, self);
}
_ => {
let stub = MachineError::functor_stub(
clause_name!("$put_bytes"),
2,
);
let addr = self.heap.to_unifiable(
HeapCellValue::Stream(stream.clone()),
);
return Err(self.error_form(
MachineError::existence_error(
self.heap.h(),
ExistenceError::Stream(addr),
),
stub,
));
}
}
}
&SystemClauseType::GetByte => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;