From 8958ea036e8dc1eb89d2c8b728a00ebc4bde8762 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 16 Jun 2020 21:13:03 +0200 Subject: [PATCH] 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. --- src/clause_types.rs | 14 +++--- src/lib/format.pl | 16 +++--- src/machine/system_calls.rs | 99 +++++++++++++++++++------------------ 3 files changed, 66 insertions(+), 63 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index 58a0bae3..18534668 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -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) } diff --git a/src/lib/format.pl b/src/lib/format.pl index 811a4c33..95a1a1da 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -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). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 025da98b..9edac576 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -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)?; -- 2.54.0