ENHANCED: partial_string/3 no longer creates atoms
As a consequence, resulting strings are now quickly reclaimed on backtracking. This addresses #2912. Test case: :- use_module(library(iso_ext)). :- use_module(library(lists)). ab(a). ab(b). Sample query: ?- length(Ls, 1_000_000), maplist(ab, Ls), partial_string(Ls, Es0, []), Es0 == Ls. Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; ... . running in constant memory.
This commit is contained in:
@@ -22,6 +22,7 @@ but they're not part of the ISO Prolog standard at the moment.
|
|||||||
copy_term/3]).
|
copy_term/3]).
|
||||||
|
|
||||||
:- use_module(library(error), [can_be/2,
|
:- use_module(library(error), [can_be/2,
|
||||||
|
must_be/2,
|
||||||
domain_error/3,
|
domain_error/3,
|
||||||
instantiation_error/1,
|
instantiation_error/1,
|
||||||
type_error/3]).
|
type_error/3]).
|
||||||
@@ -275,17 +276,15 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
|||||||
; nonvar(R)
|
; nonvar(R)
|
||||||
).
|
).
|
||||||
|
|
||||||
%% partial_string(String, L, L0)
|
%% partial_string(String, Ls0, Ls)
|
||||||
%
|
%
|
||||||
% Explicitly construct a partial string "manually". It can be used as an optimized append/3.
|
% Explicitly construct a partial string "manually". It can be used as an optimized append/3.
|
||||||
% It's not recommended to use this predicate in application code.
|
% It's not recommended to use this predicate in application code.
|
||||||
partial_string(String, L, L0) :-
|
partial_string(String, Ls0, Ls) :-
|
||||||
|
must_be(chars, String),
|
||||||
( String == [] ->
|
( String == [] ->
|
||||||
L = L0
|
Ls0 = Ls
|
||||||
; catch(atom_chars(Atom, String),
|
; '$create_partial_string'(String, Ls0, Ls)
|
||||||
error(E, _),
|
|
||||||
throw(error(E, partial_string/3))),
|
|
||||||
'$create_partial_string'(Atom, L, L0)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
%% partial_string(+String)
|
%% partial_string(+String)
|
||||||
|
|||||||
@@ -2479,30 +2479,32 @@ impl Machine {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn create_partial_string(&mut self) {
|
pub(crate) fn create_partial_string(&mut self) {
|
||||||
let atom = cell_as_atom!(self.deref_register(1));
|
let a1 = self.deref_register(1);
|
||||||
|
|
||||||
if atom == atom!("") {
|
if let Some(str_like) = self.machine_st.value_to_str_like(a1) {
|
||||||
self.machine_st.fail = true;
|
let str = match str_like {
|
||||||
return;
|
AtomOrString::String(string) => string,
|
||||||
}
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let pstr_loc_cell = step_or_resource_error!(
|
let pstr_loc_cell =
|
||||||
self.machine_st,
|
step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_pstr(&str));
|
||||||
self.machine_st.heap.allocate_pstr(&*atom.as_str())
|
|
||||||
);
|
|
||||||
|
|
||||||
let tail_loc = self.machine_st.heap.cell_len();
|
let tail_loc = self.machine_st.heap.cell_len();
|
||||||
|
|
||||||
step_or_resource_error!(
|
step_or_resource_error!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc))
|
self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc))
|
||||||
);
|
);
|
||||||
|
|
||||||
unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell);
|
unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell);
|
||||||
|
|
||||||
if !self.machine_st.fail {
|
if !self.machine_st.fail {
|
||||||
let tail = self.machine_st.registers[3];
|
let tail = self.machine_st.registers[3];
|
||||||
unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc));
|
unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user