This speeds up web servers considerably when sending binary files.
PeekCode,
PointsToContinuationResetMarker,
PutByte,
+ PutBytes,
PutChar,
PutCode,
REPL(REPLCodePtr),
&SystemClauseType::PutByte => {
clause_name!("$put_byte")
}
+ &SystemClauseType::PutBytes => {
+ clause_name!("$put_bytes")
+ }
&SystemClauseType::PutChar => {
clause_name!("$put_char")
}
("$put_byte", 2) => {
Some(SystemClauseType::PutByte)
}
+ ("$put_bytes", 2) => {
+ Some(SystemClauseType::PutBytes)
+ }
("$put_char", 2) => {
Some(SystemClauseType::PutChar)
}
format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) ->
- maplist(char_code, Cs, Bytes),
- maplist(put_byte(Stream), Bytes)
+ % maplist(char_code, Cs, Bytes) is currently a lot slower
+ % than first converting Cs to an atom, and then to codes.
+ % In the future, we can ideally avoid creating an atom here,
+ % since an atom leaves traces in the system.
+ atom_chars(A, Cs),
+ atom_codes(A, Bytes),
+ ( member(NonByte, Bytes), NonByte > 255 ->
+ char_code(Char, NonByte),
+ throw(error(representation_error(Char), format/3))
+ ; true
+ ),
+ % For binary streams, we use a specialised internal predicate
+ % that uses only a single "write" operation for efficiency.
+ '$put_bytes'(Stream, Bytes)
; maplist(put_char(Stream), Cs)
).
}
}
}
+ &SystemClauseType::PutBytes => {
+ let mut stream =
+ self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?;
+
+ let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2);
+ let bytes = self.integers_to_bytevec(temp_v!(2), stub);
+
+ 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)?;