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:
@@ -229,8 +229,8 @@ pub enum SystemClauseType {
|
|||||||
PeekCode,
|
PeekCode,
|
||||||
PointsToContinuationResetMarker,
|
PointsToContinuationResetMarker,
|
||||||
PutByte,
|
PutByte,
|
||||||
PutBytes,
|
|
||||||
PutChar,
|
PutChar,
|
||||||
|
PutChars,
|
||||||
PutCode,
|
PutCode,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
ReadQueryTerm,
|
ReadQueryTerm,
|
||||||
@@ -419,12 +419,12 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::PutByte => {
|
&SystemClauseType::PutByte => {
|
||||||
clause_name!("$put_byte")
|
clause_name!("$put_byte")
|
||||||
}
|
}
|
||||||
&SystemClauseType::PutBytes => {
|
|
||||||
clause_name!("$put_bytes")
|
|
||||||
}
|
|
||||||
&SystemClauseType::PutChar => {
|
&SystemClauseType::PutChar => {
|
||||||
clause_name!("$put_char")
|
clause_name!("$put_char")
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::PutChars => {
|
||||||
|
clause_name!("$put_chars")
|
||||||
|
}
|
||||||
&SystemClauseType::PutCode => {
|
&SystemClauseType::PutCode => {
|
||||||
clause_name!("$put_code")
|
clause_name!("$put_code")
|
||||||
}
|
}
|
||||||
@@ -560,12 +560,12 @@ impl SystemClauseType {
|
|||||||
("$put_byte", 2) => {
|
("$put_byte", 2) => {
|
||||||
Some(SystemClauseType::PutByte)
|
Some(SystemClauseType::PutByte)
|
||||||
}
|
}
|
||||||
("$put_bytes", 2) => {
|
|
||||||
Some(SystemClauseType::PutBytes)
|
|
||||||
}
|
|
||||||
("$put_char", 2) => {
|
("$put_char", 2) => {
|
||||||
Some(SystemClauseType::PutChar)
|
Some(SystemClauseType::PutChar)
|
||||||
}
|
}
|
||||||
|
("$put_chars", 2) => {
|
||||||
|
Some(SystemClauseType::PutChars)
|
||||||
|
}
|
||||||
("$put_code", 2) => {
|
("$put_code", 2) => {
|
||||||
Some(SystemClauseType::PutCode)
|
Some(SystemClauseType::PutCode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Part of Scryer Prolog.
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
This library provides the nonterminal format_//2 to describe
|
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:
|
Usage:
|
||||||
======
|
======
|
||||||
@@ -369,17 +369,15 @@ digits(uppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").
|
|||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
format(Fs, Args) :-
|
format(Fs, Args) :-
|
||||||
phrase(format_(Fs, Args), Cs),
|
current_output(Stream),
|
||||||
maplist(write, Cs).
|
format(Stream, Fs, Args).
|
||||||
|
|
||||||
format(Stream, Fs, Args) :-
|
format(Stream, Fs, Args) :-
|
||||||
phrase(format_(Fs, Args), Cs),
|
phrase(format_(Fs, Args), Cs),
|
||||||
( stream_property(Stream, type(binary)) ->
|
% we use a specialised internal predicate that uses only a
|
||||||
% For binary streams, we use a specialised internal predicate
|
% single "write" operation for efficiency. It is equivalent to
|
||||||
% that uses only a single "write" operation for efficiency.
|
% maplist(put_char(Stream), Cs). It also works for binary streams.
|
||||||
'$put_bytes'(Stream, Cs)
|
'$put_chars'(Stream, Cs).
|
||||||
; maplist(put_char(Stream), Cs)
|
|
||||||
).
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
?- phrase(cells("hello", [], 0, []), Cs).
|
?- phrase(cells("hello", [], 0, []), Cs).
|
||||||
|
|||||||
@@ -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 => {
|
&SystemClauseType::PutByte => {
|
||||||
let mut stream =
|
let mut stream =
|
||||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "put_byte", 2)?;
|
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 => {
|
&SystemClauseType::GetByte => {
|
||||||
let mut stream =
|
let mut stream =
|
||||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user