]> Repositorios git - scryer-prolog.git/commitdiff
ENHANCED: much faster format/3 for text streams
authorMarkus Triska <[email protected]>
Tue, 16 Jun 2020 19:13:03 +0000 (21:13 +0200)
committerMarkus Triska <[email protected]>
Tue, 16 Jun 2020 19:13:03 +0000 (21:13 +0200)
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
src/lib/format.pl
src/machine/system_calls.rs

index 58a0bae3d519d1f696a33be06170cd52e5e9c2b4..18534668a5724b6a61d0ce0112ba2366afb1254a 100644 (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)
             }
index 811a4c33095764134fbeaa02f01171d8f338dc1f..95a1a1dafb2e5af58ccb7a5b77065134cdc445da 100644 (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).
index 025da98b091f8067dbe4bcd8418dfeca901ff514..9edac5763cafb70bc0bf76472b846689f5ed6239 100644 (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)?;