From b85ff7db365aabc067e9e8f92a1301b1b820fd4d Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 12 Jun 2020 17:29:18 +0200 Subject: [PATCH] ENHANCED: Read more characters at once, significantly speeding up library(pio). --- src/clause_types.rs | 3 ++ src/lib/pio.pl | 58 ++++--------------------------------- src/machine/system_calls.rs | 58 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index bc8a69ea..58a0bae3 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -184,6 +184,7 @@ pub enum SystemClauseType { FlushOutput, GetByte, GetChar, + GetNChars, GetCode, GetSingleChar, ResetAttrVarState, @@ -353,6 +354,7 @@ impl SystemClauseType { &SystemClauseType::FlushOutput => clause_name!("$flush_output"), &SystemClauseType::GetByte => clause_name!("$get_byte"), &SystemClauseType::GetChar => clause_name!("$get_char"), + &SystemClauseType::GetNChars => clause_name!("$get_n_chars"), &SystemClauseType::GetCode => clause_name!("$get_code"), &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), @@ -549,6 +551,7 @@ impl SystemClauseType { ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_byte", 2) => Some(SystemClauseType::GetByte), ("$get_char", 2) => Some(SystemClauseType::GetChar), + ("$get_n_chars", 3) => Some(SystemClauseType::GetNChars), ("$get_code", 2) => Some(SystemClauseType::GetCode), ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar), ("$points_to_cont_reset_marker", 1) => { diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 4132752b..89dfc566 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -22,67 +22,21 @@ phrase_from_file(NT, File, Options) :- ; Type = text ), setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]), - ( stream_to_lazy_list(pio:Type, Stream, Xs), + ( stream_to_lazy_list(Stream, Xs), phrase(NT, Xs) ), close(Stream)) ). -stream_to_lazy_list(Type_3, Stream, Xs) :- +stream_to_lazy_list(Stream, Xs) :- stream_property(Stream, position(Pos)), - freeze(Xs, reader_step(Type_3, Stream, Pos, Xs)). + freeze(Xs, reader_step(Stream, Pos, Xs)). -reader_step(Type_3, Stream, Pos, Xs0) :- +reader_step(Stream, Pos, Xs0) :- set_stream_position(Stream, Pos), ( at_end_of_stream(Stream) -> Xs0 = [] - ; % phrase(call(call(Type_3,Stream)), Xs0,Xs), % conforming call - call(Type_3, Stream, Cs,[]), % effective call + ; '$get_n_chars'(Stream, 4096, Cs), partial_string(Cs, Xs0, Xs), - stream_to_lazy_list(Type_3, Stream, Xs) + stream_to_lazy_list(Stream, Xs) ). - -binary(Stream, Xs0, Xs) :- get_pending_bytes(Stream, Xs0, Xs). -text(Stream, Xs0, Xs) :- get_pending_chars(Stream, Xs0, Xs). - - -get_pending_chars(Stream, Chs0,Chs) :- - n_get_chars(4096, Stream, Chs, Chs0,Chs). - -% EOF means: If EOF == [], then EOF has definitely been reached, otherwise -% it is unknown and the argument remains uninstantiated. - -% To improve performance, the following predicates should be replaced -% by a fast Rust implementation that reads a number of characters (or -% bytes) at once. - -% Files that do not contain 0-bytes can even be mmapped to memory. - -n_get_chars(N0, Stream, EOF, Chs0,Chs) :- - N0 > 0, - N1 is N0-1, - get_char(Stream, Ch), - ( Ch == end_of_file - -> Chs0 = Chs, - EOF = [] - ; Chs0 = [Ch|Chs1], - n_get_chars(N1, Stream, EOF, Chs1,Chs) - ). -n_get_chars(0, _, _, Chs,Chs). - - -get_pending_bytes(Stream, Chs0,Chs) :- - n_get_bytes(4096, Stream, Chs, Chs0,Chs). - -n_get_bytes(N0, Stream, EOF, Chs0,Chs) :- - N0 > 0, - N1 is N0-1, - get_byte(Stream, Byte), - ( Byte == -1 - -> Chs0 = Chs, - EOF = [] - ; char_code(Ch, Byte), - Chs0 = [Ch|Chs1], - n_get_bytes(N1, Stream, EOF, Chs1,Chs) - ). -n_get_bytes(0, _, _, Chs,Chs). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 2ff4b7d9..7a05049f 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2256,6 +2256,64 @@ impl MachineState { } } } + &SystemClauseType::GetNChars => { + let stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "get_n_chars", 3)?; + + let num = + match Number::try_from((self[temp_v!(2)], &self.heap)) { + Ok(Number::Fixnum(n)) => { + usize::try_from(n).unwrap() + } + Ok(Number::Integer(n)) => { + match n.to_usize() { + Some(u) => { u } + _ => { self.fail = true; return Ok(()); } + } + } + _ => { unreachable!() } + }; + + let chars = { + let mut str = String::new(); + + if stream.options.stream_type == StreamType::Binary { + let mut mstream = stream.clone(); + for _ in 0..num { + let mut b = [0u8; 1]; + + match mstream.read(&mut b) { + Ok(1) => { + str.push(b[0] as char); + } + _ => { + break; + } + } + } + } else { + let mut iter = self.open_parsing_stream(stream.clone(), + "get_n_chars", + 2, + )?; + + for _ in 0..num { + let result = iter.next(); + + match result { + Some(Ok(c)) => { + str.push(c); + } + _ => { break; + } + } + } + } + str + }; + let str = self.heap.put_complete_string(&chars); + self.unify(self[temp_v!(3)], str); + } &SystemClauseType::GetCode => { let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "get_code", 2)?; -- 2.54.0