[m-rev.] for review: string.between
Peter Wang
novalazy at gmail.com
Fri Jun 10 18:07:54 AEST 2011
Branches: main
Deprecate string.substring, string.foldl_substring, etc. in favour of
new procedures named string.between, string.foldl_between, etc.
The "between" procedures take a pair of [Start, End) endpoints instead
of Start, Count arguments. The reasons for this change are:
- the "between" procedures are more convenient
- "between" should be unambiguous. You can guess that it takes an End
argument instead of a Count argument without looking up the manual.
- Count arguments necessarily counted code units, but when working with
non-ASCII strings, almost the only way that the values would be arrived at
is by substracting one end point from another.
- it paves the way for a potential change to replace string offsets with an
abstract type. We cannot do that if users regularly have to perform a
subtraction between two offsets.
library/string.m:
Add string.foldl_between, string.foldl2_between,
string.foldr_between, string.between.
Deprecate the old substring names.
Replace string.substring_by_codepoint by string.between_codepoints.
compiler/elds_to_erlang.m:
compiler/error_util.m:
compiler/rbmm.live_variable_analysis.m:
compiler/timestamp.m:
extras/posix/samples/mdprof_cgid.m:
library/bitmap.m:
library/integer.m:
library/lexer.m:
library/parsing_utils.m:
mdbcomp/trace_counts.m:
profiler/demangle.m:
Conform to changes.
tests/general/Mercury.options:
tests/general/string_foldl_substring.exp:
tests/general/string_foldl_substring.m:
tests/general/string_foldr_substring.exp:
tests/general/string_foldr_substring.m:
tests/hard_coded/Mercury.options:
tests/hard_coded/string_substring.m:
Test both between and substring procedures.
tests/hard_coded/string_codepoint.exp:
tests/hard_coded/string_codepoint.exp2:
tests/hard_coded/string_codepoint.m:
Update names in test outputs.
NEWS:
Announce the change.
diff --git a/NEWS b/NEWS
index 172fe6b..fa2cb74 100644
--- a/NEWS
+++ b/NEWS
@@ -108,15 +108,24 @@ Changes to the Mercury standard library:
bitmap.new/2
hash_table.new/3
hash_table.new_default/1
- store.new/1
semaphore.new/1
semaphore.new/3
+ store.new/1
+ string.foldl2_substring/8
+ string.foldl_substring/5
+ string.foldl_substring/6
+ string.foldr_substring/5
+ string.foldr_substring/6
+ string.substring/3
+ string.substring/4
+ string.unsafe_substring/3
+ string.unsafe_substring/4
version_array.new/2
version_array2d.new/3
version_bitmap.new/2
version_hash_table.new/3
- version_hash_table.unsafe_new/3
version_hash_table.new_default/1
+ version_hash_table.unsafe_new/3
version_hash_table.unsafe_new_default/1
version_store.new/0
diff --git a/compiler/elds_to_erlang.m b/compiler/elds_to_erlang.m
index d8f07a0..a176e49 100644
--- a/compiler/elds_to_erlang.m
+++ b/compiler/elds_to_erlang.m
@@ -791,9 +791,9 @@ output_term(ModuleInfo, VarSet, Indent, Term, !IO) :-
output_float(Float, !IO) :-
S = string.from_float(Float),
( digit_then_e(S, no, 0, Pos) ->
- io.write_string(string.substring(S, 0, Pos), !IO),
+ io.write_string(string.between(S, 0, Pos), !IO),
io.write_string(".0", !IO),
- io.write_string(string.substring(S, Pos, length(S)), !IO)
+ io.write_string(string.between(S, Pos, length(S)), !IO)
;
io.write_string(S, !IO)
).
diff --git a/compiler/error_util.m b/compiler/error_util.m
index 6e79a2f..332cb29 100644
--- a/compiler/error_util.m
+++ b/compiler/error_util.m
@@ -1342,7 +1342,7 @@ break_into_words(String, Words0, Words) :-
break_into_words_from(String, Cur, Words0, Words) :-
( find_word_start(String, Cur, Start) ->
find_word_end(String, Start, End),
- string.substring(String, Start, End - Start, WordStr),
+ string.between(String, Start, End, WordStr),
break_into_words_from(String, End, [plain_word(WordStr) | Words0],
Words)
;
diff --git a/compiler/rbmm.live_variable_analysis.m b/compiler/rbmm.live_variable_analysis.m
index c0aa0d5..0726b42 100644
--- a/compiler/rbmm.live_variable_analysis.m
+++ b/compiler/rbmm.live_variable_analysis.m
@@ -385,8 +385,7 @@ collect_void_vars(ProgPoint, ProducedSet, ProcInfo, !ProcVoidVar) :-
void_var(Varset, Var, !VoidVars) :-
mercury_var_to_string(Varset, no, Var) = VarName,
- string.substring(VarName, 0, 1, FirstChar),
- ( FirstChar = "_" ->
+ ( string.index(VarName, 0, '_') ->
set.insert(Var, !VoidVars)
;
true
diff --git a/compiler/timestamp.m b/compiler/timestamp.m
index 68b53b7..d9ed7d0 100644
--- a/compiler/timestamp.m
+++ b/compiler/timestamp.m
@@ -161,35 +161,35 @@ string_to_timestamp(Timestamp) = timestamp(Timestamp) :-
string.all_match(plausible_timestamp_char, Timestamp),
string.length(Timestamp) : int = string.length("yyyy-mm-dd hh:mm:ss")
->
- string.to_int(string.unsafe_substring(Timestamp, 0, 4), _),
+ string.to_int(string.unsafe_between(Timestamp, 0, 4), _),
string.unsafe_index(Timestamp, 4, '-'),
- string.to_int(string.unsafe_substring(Timestamp, 5, 2), Month),
+ string.to_int(string.unsafe_between(Timestamp, 5, 7), Month),
Month >= 1,
Month =< 12,
string.unsafe_index(Timestamp, 7, '-'),
- string.to_int(string.unsafe_substring(Timestamp, 8, 2), Day),
+ string.to_int(string.unsafe_between(Timestamp, 8, 10), Day),
Day >= 1,
Day =< 31,
string.unsafe_index(Timestamp, 10, ' '),
- string.to_int(string.unsafe_substring(Timestamp, 11, 2), Hour),
+ string.to_int(string.unsafe_between(Timestamp, 11, 13), Hour),
Hour >= 0,
Hour =< 23,
string.unsafe_index(Timestamp, 13, ':'),
- string.to_int(string.unsafe_substring(Timestamp, 14, 2), Minute),
+ string.to_int(string.unsafe_between(Timestamp, 14, 16), Minute),
Minute >= 0,
Minute =< 59,
string.unsafe_index(Timestamp, 16, ':'),
- string.to_int(string.unsafe_substring(Timestamp, 17, 2), Second),
+ string.to_int(string.unsafe_between(Timestamp, 17, 19), Second),
Second >= 0,
Second =< 61 % Seconds 60 and 61 are for leap seconds.
;
diff --git a/extras/posix/samples/mdprof_cgid.m b/extras/posix/samples/mdprof_cgid.m
index 92c6712..4c138a7 100644
--- a/extras/posix/samples/mdprof_cgid.m
+++ b/extras/posix/samples/mdprof_cgid.m
@@ -267,7 +267,7 @@ handle_request_2(Data, Path, !IO) :-
%
(if string.sub_string_search(Path, "?", QuesIndex) then
Length = string.length(Path),
- QueryString = string.substring(Path, QuesIndex + 1, Length)
+ QueryString = string.between(Path, QuesIndex + 1, Length)
else
QueryString = ""
),
diff --git a/library/bitmap.m b/library/bitmap.m
index b0a92d0..d2551ac 100644
--- a/library/bitmap.m
+++ b/library/bitmap.m
@@ -1426,21 +1426,18 @@ to_string_chars(Index, BM, !Chars) :-
).
from_string(Str) = BM :-
- Len = length(Str),
- ( if Len >= 4 then
- Str ^ unsafe_elem(0) = ('<'),
- char.is_digit(Str ^ unsafe_elem(1)),
- Str ^ unsafe_elem(Len - 1) = ('>'),
- string.sub_string_search(Str, ":", Colon),
- SizeStr = string.unsafe_substring(Str, 1, Colon - 1),
- string.to_int(SizeStr, Size),
- ( if Size >= 0 then
- BM0 = allocate_bitmap(Size),
- hex_chars_to_bitmap(Str, Colon + 1, Len - 1, 0, BM0, BM)
- else
- fail
- )
- else
+ string.unsafe_index_next(Str, 0, Start, '<'),
+ string.unsafe_index(Str, Start, Char),
+ char.is_digit(Char),
+ string.unsafe_prev_index(Str, length(Str), End, '>'),
+ string.sub_string_search_start(Str, ":", Start, Colon),
+ SizeStr = string.unsafe_between(Str, Start, Colon),
+ string.to_int(SizeStr, Size),
+ ( Size >= 0 ->
+ BM0 = allocate_bitmap(Size),
+ string.unsafe_index_next(Str, Colon, AfterColon, _),
+ hex_chars_to_bitmap(Str, AfterColon, End, 0, BM0, BM)
+ ;
fail
).
diff --git a/library/integer.m b/library/integer.m
index 240723b..7394ae3 100644
--- a/library/integer.m
+++ b/library/integer.m
@@ -1221,16 +1221,16 @@ integer.from_base_string(Base0, String) = Integer :-
Len = string.length(String),
( Char = ('-') ->
Len > 1,
- string.foldl_substring(accumulate_integer(Base), String, 1, Len - 1,
+ string.foldl_between(accumulate_integer(Base), String, 1, Len,
integer.zero, N),
Integer = -N
; Char = ('+') ->
Len > 1,
- string.foldl_substring(accumulate_integer(Base), String, 1, Len - 1,
+ string.foldl_between(accumulate_integer(Base), String, 1, Len,
integer.zero, N),
Integer = N
;
- string.foldl_substring(accumulate_integer(Base), String, 0, Len,
+ string.foldl_between(accumulate_integer(Base), String, 0, Len,
integer.zero, N),
Integer = N
).
diff --git a/library/lexer.m b/library/lexer.m
index 7fb96dc..6b75e6e 100644
--- a/library/lexer.m
+++ b/library/lexer.m
@@ -348,8 +348,7 @@ string_ungetchar(String, Posn0, Posn) :-
grab_string(String, Posn0, SubString, Posn, Posn) :-
Posn0 = posn(_, _, Offset0),
Posn = posn(_, _, Offset),
- Count = Offset - Offset0,
- string.unsafe_substring(String, Offset0, Count, SubString).
+ string.unsafe_between(String, Offset0, Offset, SubString).
:- pred string_set_line_number(int::in, posn::in, posn::out) is det.
diff --git a/library/parsing_utils.m b/library/parsing_utils.m
index a29138a..dbfacbb 100644
--- a/library/parsing_utils.m
+++ b/library/parsing_utils.m
@@ -517,8 +517,7 @@ char_in_class(CharClass, Src, Char, !PS) :-
input_substring(Src, Start, EndPlusOne, Substring) :-
promise_pure (
EndPlusOne =< Src ^ input_length,
- Substring =
- unsafe_substring(Src ^ input_string, Start, EndPlusOne - Start),
+ Substring = unsafe_between(Src ^ input_string, Start, EndPlusOne),
impure record_progress(Src, Start)
).
diff --git a/library/string.m b/library/string.m
index 8ef25f7..8604de2 100644
--- a/library/string.m
+++ b/library/string.m
@@ -709,12 +709,80 @@
:- mode string.foldl2(pred(in, in, out, in, out) is multi,
in, in, out, in, out) is multi.
- % string.foldl_substring(Closure, String, Start, Count, !Acc)
+ % string.foldl_between(Closure, String, Start, End, !Acc)
% is equivalent to string.foldl(Closure, SubString, !Acc)
- % where SubString = string.substring(String, Start, Count).
+ % where SubString = string.between(String, Start, End).
+ %
+ % `Start' and `End' are in terms of code units.
+ %
+:- func string.foldl_between(func(char, A) = A, string, int, int, A) = A.
+:- pred string.foldl_between(pred(char, A, A), string, int, int, A, A).
+:- mode string.foldl_between(pred(in, in, out) is det, in, in, in,
+ in, out) is det.
+:- mode string.foldl_between(pred(in, di, uo) is det, in, in, in,
+ di, uo) is det.
+:- mode string.foldl_between(pred(in, in, out) is semidet, in, in, in,
+ in, out) is semidet.
+:- mode string.foldl_between(pred(in, in, out) is nondet, in, in, in,
+ in, out) is nondet.
+:- mode string.foldl_between(pred(in, in, out) is multi, in, in, in,
+ in, out) is multi.
+
+ % string.foldl2_between(Closure, String, Start, End, !Acc1, !Acc2)
+ % A variant of string.foldl_between with two accumulators.
+ %
+ % `Start' and `End' are in terms of code units.
+ %
+:- pred string.foldl2_between(pred(char, A, A, B, B),
+ string, int, int, A, A, B, B).
+:- mode string.foldl2_between(pred(in, di, uo, di, uo) is det,
+ in, in, in, di, uo, di, uo) is det.
+:- mode string.foldl2_between(pred(in, in, out, di, uo) is det,
+ in, in, in, in, out, di, uo) is det.
+:- mode string.foldl2_between(pred(in, in, out, in, out) is det,
+ in, in, in, in, out, in, out) is det.
+:- mode string.foldl2_between(pred(in, in, out, in, out) is semidet,
+ in, in, in, in, out, in, out) is semidet.
+:- mode string.foldl2_between(pred(in, in, out, in, out) is nondet,
+ in, in, in, in, out, in, out) is nondet.
+:- mode string.foldl2_between(pred(in, in, out, in, out) is multi,
+ in, in, in, in, out, in, out) is multi.
+
+ % string.foldr(Closure, String, !Acc):
+ % As string.foldl/4, except that processing proceeds right-to-left.
+ %
+:- func string.foldr(func(char, T) = T, string, T) = T.
+:- pred string.foldr(pred(char, T, T), string, T, T).
+:- mode string.foldr(pred(in, in, out) is det, in, in, out) is det.
+:- mode string.foldr(pred(in, di, uo) is det, in, di, uo) is det.
+:- mode string.foldr(pred(in, in, out) is semidet, in, in, out) is semidet.
+:- mode string.foldr(pred(in, in, out) is nondet, in, in, out) is nondet.
+:- mode string.foldr(pred(in, in, out) is multi, in, in, out) is multi.
+
+ % string.foldr_between(Closure, String, Start, End, !Acc)
+ % is equivalent to string.foldr(Closure, SubString, !Acc)
+ % where SubString = string.between(String, Start, End).
+ %
+ % `Start' and `End' are in terms of code units.
%
- % `Start' and `Count' are in terms of code units.
+:- func string.foldr_between(func(char, T) = T, string, int, int, T) = T.
+:- pred string.foldr_between(pred(char, T, T), string, int, int, T, T).
+:- mode string.foldr_between(pred(in, in, out) is det, in, in, in,
+ in, out) is det.
+:- mode string.foldr_between(pred(in, di, uo) is det, in, in, in,
+ di, uo) is det.
+:- mode string.foldr_between(pred(in, in, out) is semidet, in, in, in,
+ in, out) is semidet.
+:- mode string.foldr_between(pred(in, in, out) is nondet, in, in, in,
+ in, out) is nondet.
+:- mode string.foldr_between(pred(in, in, out) is multi, in, in, in,
+ in, out) is multi.
+
+ % string.foldl_substring(Closure, String, Start, Count, !Acc)
+ % Please use string.foldl_between instead.
%
+:- pragma obsolete(string.foldl_substring/5).
+:- pragma obsolete(string.foldl_substring/6).
:- func string.foldl_substring(func(char, A) = A, string, int, int, A) = A.
:- pred string.foldl_substring(pred(char, A, A), string, int, int, A, A).
:- mode string.foldl_substring(pred(in, in, out) is det, in, in, in,
@@ -728,11 +796,10 @@
:- mode string.foldl_substring(pred(in, in, out) is multi, in, in, in,
in, out) is multi.
- % string.foldl_substring2(Closure, String, Start, Count, !Acc1, !Acc2)
- % A variant of string.foldl_substring with two accumulators.
- %
- % `Start' and `Count' are in terms of code units.
+ % string.foldl2_substring(Closure, String, Start, Count, !Acc1, !Acc2)
+ % Please use string.foldl2_between instead.
%
+:- pragma obsolete(string.foldl2_substring/8).
:- pred string.foldl2_substring(pred(char, A, A, B, B),
string, int, int, A, A, B, B).
:- mode string.foldl2_substring(pred(in, di, uo, di, uo) is det,
@@ -748,23 +815,11 @@
:- mode string.foldl2_substring(pred(in, in, out, in, out) is multi,
in, in, in, in, out, in, out) is multi.
- % string.foldr(Closure, String, !Acc):
- % As string.foldl/4, except that processing proceeds right-to-left.
- %
-:- func string.foldr(func(char, T) = T, string, T) = T.
-:- pred string.foldr(pred(char, T, T), string, T, T).
-:- mode string.foldr(pred(in, in, out) is det, in, in, out) is det.
-:- mode string.foldr(pred(in, di, uo) is det, in, di, uo) is det.
-:- mode string.foldr(pred(in, in, out) is semidet, in, in, out) is semidet.
-:- mode string.foldr(pred(in, in, out) is nondet, in, in, out) is nondet.
-:- mode string.foldr(pred(in, in, out) is multi, in, in, out) is multi.
-
% string.foldr_substring(Closure, String, Start, Count, !Acc)
- % is equivalent to string.foldr(Closure, SubString, !Acc)
- % where SubString = string.substring(String, Start, Count).
- %
- % `Start' and `Count' are in terms of code units.
+ % Please use string.foldr_between instead.
%
+:- pragma obsolete(string.foldr_substring/5).
+:- pragma obsolete(string.foldr_substring/6).
:- func string.foldr_substring(func(char, T) = T, string, int, int, T) = T.
:- pred string.foldr_substring(pred(char, T, T), string, int, int, T, T).
:- mode string.foldr_substring(pred(in, in, out) is det, in, in, in,
@@ -873,40 +928,58 @@
:- func string.right_by_codepoint(string::in, int::in) = (string::uo) is det.
:- pred string.right_by_codepoint(string::in, int::in, string::uo) is det.
- % string.substring(String, Start, Count, Substring):
- % `Substring' is first the `Count' code _units_ in what would remain
- % of `String' after the first `Start' code _units_ were removed.
+ % string.between(String, Start, End, Substring):
+ % `Substring' consists of the segment of `String' within the half-open
+ % interval [Start, End), where `Start' and `End' are code unit offsets.
% (If `Start' is out of the range [0, length of `String'], it is treated
% as if it were the nearest end-point of that range.
- % If `Count' is out of the range [0, length of `String' - `Start'],
+ % If `End' is out of the range [`Start', length of `String'],
% it is treated as if it were the nearest end-point of that range.)
%
+:- func string.between(string::in, int::in, int::in) = (string::uo) is det.
+:- pred string.between(string::in, int::in, int::in, string::uo) is det.
+
+ % string.substring(String, Start, Count, Substring):
+ % Please use string.between instead.
+ %
+:- pragma obsolete(string.substring/3).
+:- pragma obsolete(string.substring/4).
:- func string.substring(string::in, int::in, int::in) = (string::uo) is det.
:- pred string.substring(string::in, int::in, int::in, string::uo) is det.
- % string.substring_by_codepoint(String, Start, Count, Substring):
- % `Substring' is first the `Count' code points in what would remain
- % of `String' after the first `Start' code points were removed.
+ % string.between_codepoints(String, Start, End, Substring):
+ % `Substring' is the part of `String' between the code point positions
+ % `Start' and `End'.
% (If `Start' is out of the range [0, length of `String'], it is treated
% as if it were the nearest end-point of that range.
- % If `Count' is out of the range [0, length of `String' - `Start'],
+ % If `End' is out of the range [`Start', length of `String'],
% it is treated as if it were the nearest end-point of that range.)
%
-:- func string.substring_by_codepoint(string::in, int::in, int::in)
+:- func string.between_codepoints(string::in, int::in, int::in)
= (string::uo) is det.
-:- pred string.substring_by_codepoint(string::in, int::in, int::in, string::uo)
+:- pred string.between_codepoints(string::in, int::in, int::in, string::uo)
is det.
- % string.unsafe_substring(String, Start, Count, Substring):
- % `Substring' is first the `Count' code _units_ in what would remain
- % of `String' after the first `Start' code _units_ were removed.
- % WARNING: if `Start' is out of the range [0, length of `String'],
- % or if `Count' is out of the range [0, length of `String' - `Start'],
+ % string.unsafe_between(String, Start, End, Substring):
+ % `Substring' consists of the segment of `String' within the half-open
+ % interval [Start, End), where `Start' and `End' are code unit offsets.
+ % WARNING: if `Start' is out of the range [0, length of `String'] or
+ % `End' is out of the range [`Start', length of `String']
% then the behaviour is UNDEFINED. Use with care!
% This version takes time proportional to the length of the substring,
% whereas string.substring may take time proportional to the length
% of the whole string.
%
+:- func string.unsafe_between(string::in, int::in, int::in) = (string::uo)
+ is det.
+:- pred string.unsafe_between(string::in, int::in, int::in, string::uo)
+ is det.
+
+ % string.unsafe_substring(String, Start, Count, Substring):
+ % Please use string.unsafe_between instead.
+ %
+:- pragma obsolete(string.unsafe_substring/3).
+:- pragma obsolete(string.unsafe_substring/4).
:- func string.unsafe_substring(string::in, int::in, int::in) = (string::uo)
is det.
:- pred string.unsafe_substring(string::in, int::in, int::in, string::uo)
@@ -1083,11 +1156,11 @@
string.replace(Str, Pat, Subst, Result) :-
sub_string_search(Str, Pat, Index),
- Initial = string.unsafe_substring(Str, 0, Index),
+ Initial = string.unsafe_between(Str, 0, Index),
BeginAt = Index + string.length(Pat),
- Length = string.length(Str) - BeginAt,
- Final = string.unsafe_substring(Str, BeginAt, Length),
+ EndAt = string.length(Str),
+ Final = string.unsafe_between(Str, BeginAt, EndAt),
Result = string.append_list([Initial, Subst, Final]).
@@ -1108,14 +1181,12 @@ string.replace_all(Str, Pat, Subst, Result) :-
string.replace_all_2(Str, Pat, Subst, PatLength, BeginAt, Result0) = Result :-
( sub_string_search_start(Str, Pat, BeginAt, Index) ->
- Length = Index - BeginAt,
- Initial = string.unsafe_substring(Str, BeginAt, Length),
+ Initial = string.unsafe_between(Str, BeginAt, Index),
Start = Index + PatLength,
Result = string.replace_all_2(Str, Pat, Subst, PatLength, Start,
[Subst, Initial | Result0])
;
- Length = string.length(Str) - BeginAt,
- EndString = string.unsafe_substring(Str, BeginAt, Length),
+ EndString = string.unsafe_between(Str, BeginAt, length(Str)),
Result = [EndString | Result0]
).
@@ -1127,13 +1198,12 @@ string.base_string_to_int(Base, String, Int) :-
Len = string.count_codepoints(String),
( Char = ('-') ->
Len > 1,
- foldl_substring(accumulate_negative_int(Base), String, 1,
- Len - 1, 0, Int)
+ foldl_between(accumulate_negative_int(Base), String, 1, Len, 0, Int)
; Char = ('+') ->
Len > 1,
- foldl_substring(accumulate_int(Base), String, 1, Len - 1, 0, Int)
+ foldl_between(accumulate_int(Base), String, 1, Len, 0, Int)
;
- foldl_substring(accumulate_int(Base), String, 0, Len, 0, Int)
+ foldl_between(accumulate_int(Base), String, 0, Len, 0, Int)
).
:- pred accumulate_int(int::in, char::in, int::in, int::out) is semidet.
@@ -1182,71 +1252,69 @@ string.det_set_char(Char, Int, String0, String) :-
string.foldl(Closure, String, !Acc) :-
string.length(String, Length),
- string.foldl_substring(Closure, String, 0, Length, !Acc).
+ string.foldl_between(Closure, String, 0, Length, !Acc).
string.foldl2(Closure, String, !Acc1, !Acc2) :-
string.length(String, Length),
- string.foldl2_substring(Closure, String, 0, Length, !Acc1, !Acc2).
+ string.foldl2_between(Closure, String, 0, Length, !Acc1, !Acc2).
-string.foldl_substring(Closure, String, Start0, Count0, !Acc) :-
+string.foldl_between(Closure, String, Start0, End0, !Acc) :-
Start = max(0, Start0),
- Count = min(Count0, length(String) - Start),
- End = Start + Count,
- string.foldl_substring_2(Closure, String, Start, End, !Acc).
+ End = min(End0, length(String)),
+ string.foldl_between_2(Closure, String, Start, End, !Acc).
-string.foldl2_substring(Closure, String, Start0, Count0, !Acc1, !Acc2) :-
+string.foldl2_between(Closure, String, Start0, End0, !Acc1, !Acc2) :-
Start = max(0, Start0),
- Count = min(Count0, length(String) - Start),
- End = Start + Count,
- string.foldl2_substring_2(Closure, String, Start, End, !Acc1, !Acc2).
+ End = min(End0, length(String)),
+ string.foldl2_between_2(Closure, String, Start, End, !Acc1, !Acc2).
-:- pred string.foldl_substring_2(pred(char, A, A), string, int, int, A, A).
-:- mode string.foldl_substring_2(pred(in, di, uo) is det, in, in, in,
+:- pred string.foldl_between_2(pred(char, A, A), string, int, int, A, A).
+:- mode string.foldl_between_2(pred(in, di, uo) is det, in, in, in,
di, uo) is det.
-:- mode string.foldl_substring_2(pred(in, in, out) is det, in, in, in,
+:- mode string.foldl_between_2(pred(in, in, out) is det, in, in, in,
in, out) is det.
-:- mode string.foldl_substring_2(pred(in, in, out) is semidet, in, in, in,
+:- mode string.foldl_between_2(pred(in, in, out) is semidet, in, in, in,
in, out) is semidet.
-:- mode string.foldl_substring_2(pred(in, in, out) is nondet, in, in, in,
+:- mode string.foldl_between_2(pred(in, in, out) is nondet, in, in, in,
in, out) is nondet.
-:- mode string.foldl_substring_2(pred(in, in, out) is multi, in, in, in,
+:- mode string.foldl_between_2(pred(in, in, out) is multi, in, in, in,
in, out) is multi.
-string.foldl_substring_2(Closure, String, I, End, !Acc) :-
+string.foldl_between_2(Closure, String, I, End, !Acc) :-
(
I < End,
string.unsafe_index_next(String, I, J, Char),
J =< End
->
Closure(Char, !Acc),
- string.foldl_substring_2(Closure, String, J, End, !Acc)
+ string.foldl_between_2(Closure, String, J, End, !Acc)
;
true
).
-:- pred string.foldl2_substring_2(pred(char, A, A, B, B), string, int, int,
+:- pred string.foldl2_between_2(pred(char, A, A, B, B), string, int, int,
A, A, B, B).
-:- mode string.foldl2_substring_2(pred(in, di, uo, di, uo) is det,
+:- mode string.foldl2_between_2(pred(in, di, uo, di, uo) is det,
in, in, in, di, uo, di, uo) is det.
-:- mode string.foldl2_substring_2(pred(in, in, out, di, uo) is det,
+:- mode string.foldl2_between_2(pred(in, in, out, di, uo) is det,
in, in, in, in, out, di, uo) is det.
-:- mode string.foldl2_substring_2(pred(in, in, out, in, out) is det,
+:- mode string.foldl2_between_2(pred(in, in, out, in, out) is det,
in, in, in, in, out, in, out) is det.
-:- mode string.foldl2_substring_2(pred(in, in, out, in, out) is semidet,
+:- mode string.foldl2_between_2(pred(in, in, out, in, out) is semidet,
in, in, in, in, out, in, out) is semidet.
-:- mode string.foldl2_substring_2(pred(in, in, out, in, out) is nondet,
+:- mode string.foldl2_between_2(pred(in, in, out, in, out) is nondet,
in, in, in, in, out, in, out) is nondet.
-:- mode string.foldl2_substring_2(pred(in, in, out, in, out) is multi,
+:- mode string.foldl2_between_2(pred(in, in, out, in, out) is multi,
in, in, in, in, out, in, out) is multi.
-string.foldl2_substring_2(Closure, String, I, End, !Acc1, !Acc2) :-
+string.foldl2_between_2(Closure, String, I, End, !Acc1, !Acc2) :-
(
I < End,
string.unsafe_index_next(String, I, J, Char),
J =< End
->
Closure(Char, !Acc1, !Acc2),
- string.foldl2_substring_2(Closure, String, J, End, !Acc1, !Acc2)
+ string.foldl2_between_2(Closure, String, J, End, !Acc1, !Acc2)
;
true
).
@@ -1255,43 +1323,62 @@ string.foldr(F, String, Acc0) = Acc :-
Closure = ( pred(X::in, Y::in, Z::out) is det :- Z = F(X, Y)),
string.foldr(Closure, String, Acc0, Acc).
-string.foldr_substring(F, String, Start, Count, Acc0) = Acc :-
+string.foldr_between(F, String, Start, Count, Acc0) = Acc :-
Closure = ( pred(X::in, Y::in, Z::out) is det :- Z = F(X, Y) ),
- string.foldr_substring(Closure, String, Start, Count, Acc0, Acc).
+ string.foldr_between(Closure, String, Start, Count, Acc0, Acc).
string.foldr(Closure, String, Acc0, Acc) :-
- string.foldr_substring(Closure, String, 0, length(String), Acc0, Acc).
+ string.foldr_between(Closure, String, 0, length(String), Acc0, Acc).
-string.foldr_substring(Closure, String, Start0, Count0, Acc0, Acc) :-
+string.foldr_between(Closure, String, Start0, End0, Acc0, Acc) :-
Start = max(0, Start0),
- Count = min(Count0, length(String) - Start),
- End = Start + Count,
- string.foldr_substring_2(Closure, String, Start, End, Acc0, Acc).
+ End = min(End0, length(String)),
+ string.foldr_between_2(Closure, String, Start, End, Acc0, Acc).
-:- pred string.foldr_substring_2(pred(char, T, T), string, int, int, T, T).
-:- mode string.foldr_substring_2(pred(in, in, out) is det, in, in, in,
+:- pred string.foldr_between_2(pred(char, T, T), string, int, int, T, T).
+:- mode string.foldr_between_2(pred(in, in, out) is det, in, in, in,
in, out) is det.
-:- mode string.foldr_substring_2(pred(in, di, uo) is det, in, in, in,
+:- mode string.foldr_between_2(pred(in, di, uo) is det, in, in, in,
di, uo) is det.
-:- mode string.foldr_substring_2(pred(in, in, out) is semidet, in, in, in,
+:- mode string.foldr_between_2(pred(in, in, out) is semidet, in, in, in,
in, out) is semidet.
-:- mode string.foldr_substring_2(pred(in, in, out) is nondet, in, in, in,
+:- mode string.foldr_between_2(pred(in, in, out) is nondet, in, in, in,
in, out) is nondet.
-:- mode string.foldr_substring_2(pred(in, in, out) is multi, in, in, in,
+:- mode string.foldr_between_2(pred(in, in, out) is multi, in, in, in,
in, out) is multi.
-string.foldr_substring_2(Closure, String, Start, I, !Acc) :-
+string.foldr_between_2(Closure, String, Start, I, !Acc) :-
(
I > Start,
string.unsafe_prev_index(String, I, J, Char),
J >= Start
->
Closure(Char, !Acc),
- string.foldr_substring_2(Closure, String, Start, J, !Acc)
+ string.foldr_between_2(Closure, String, Start, J, !Acc)
;
true
).
+string.foldl_substring(F, String, Start, Count, Acc0) = Acc :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ Acc = string.foldl_between(F, String, ClampStart, ClampEnd, Acc0).
+
+string.foldl_substring(Closure, String, Start, Count, !Acc) :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ string.foldl_between(Closure, String, ClampStart, ClampEnd, !Acc).
+
+string.foldl2_substring(Closure, String, Start, Count, !Acc1, !Acc2) :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ string.foldl2_between(Closure, String, ClampStart, ClampEnd, !Acc1, !Acc2).
+
+string.foldr_substring(F, String, Start, Count, Acc0) = Acc :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ Acc = string.foldr_between(F, String, ClampStart, ClampEnd, Acc0).
+
+string.foldr_substring(Closure, String, Start, Count, !Acc) :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ string.foldr_between(Closure, String, ClampStart, ClampEnd, !Acc).
+
string.left(String, Count, LeftString) :-
string.split(String, Count, LeftString, _RightString).
@@ -1372,7 +1459,7 @@ prefix_2_iii(String, Prefix, I) :-
prefix_2_ioi(String, Prefix, Cur) :-
(
- Prefix = unsafe_substring(String, 0, Cur)
+ Prefix = unsafe_between(String, 0, Cur)
;
string.unsafe_index_next(String, Cur, Next, _),
prefix_2_ioi(String, Prefix, Next)
@@ -1405,7 +1492,7 @@ suffix_2_iiii(String, Suffix, I, Offset, Len) :-
suffix_2_ioii(String, Suffix, Cur, Len) :-
(
- string.unsafe_substring(String, Cur, Len - Cur, Suffix)
+ string.unsafe_between(String, Cur, Len, Suffix)
;
string.unsafe_prev_index(String, Cur, Prev, _),
suffix_2_ioii(String, Suffix, Prev, Len)
@@ -2567,7 +2654,8 @@ sub_string_search_start_2(String, SubString, I, Length, SubLength, Index) :-
% mode of substring, so this ends up calling the (in, in, in) = out
% mode and then doing the unification. This will create a lot of
% unnecessary garbage.
- substring(String, I, SubLength) = SubString
+ % XXX This will abort if either index is not at a code point boundary.
+ between(String, I, I + SubLength) = SubString
->
Index = I
;
@@ -3256,7 +3344,7 @@ format_char(Flags, Width, Char) = String :-
format_string(Flags, Width, Prec, OldStr) = NewStr :-
(
Prec = yes(NumChars),
- PrecStr = string.substring_by_codepoint(OldStr, 0, NumChars)
+ PrecStr = string.left_by_codepoint(OldStr, NumChars)
;
Prec = no,
PrecStr = OldStr
@@ -3433,7 +3521,7 @@ format_float(Flags, Width, Prec, Float) = NewFloat :-
Prec = yes(0)
->
PrecStrLen = string.count_codepoints(PrecStr),
- PrecModStr = string.substring(PrecStr, 0, PrecStrLen - 1)
+ PrecModStr = string.between(PrecStr, 0, PrecStrLen - 1)
;
PrecModStr = PrecStr
)
@@ -3785,8 +3873,8 @@ change_to_g_notation(Float, Prec, E, Flags) = FormattedFloat :-
split_at_exponent(ScientificFloat, BaseStr, ExponentStr),
Exp = string.det_to_int(ExponentStr),
split_at_decimal_point(BaseStr, MantissaStr, FractionStr),
- RestMantissaStr = substring(FractionStr, 0, Exp),
- NewFraction = substring(FractionStr, Exp, Prec - Exp - 1),
+ RestMantissaStr = between(FractionStr, 0, Exp),
+ NewFraction = between(FractionStr, Exp, Prec - 1),
FormattedFloat0 = MantissaStr ++ RestMantissaStr
++ "." ++ NewFraction
),
@@ -3941,7 +4029,7 @@ calculate_base_unsafe(Float, Prec) = Exp :-
split_at_decimal_point(Float, MantissaStr, FractionStr),
( Place < 0 ->
DecimalPos = abs(Place),
- PaddedMantissaStr = string.substring(FractionStr, 0, DecimalPos),
+ PaddedMantissaStr = string.between(FractionStr, 0, DecimalPos),
% Get rid of superfluous zeros.
MantissaInt = string.det_to_int(PaddedMantissaStr),
@@ -3949,11 +4037,11 @@ calculate_base_unsafe(Float, Prec) = Exp :-
% Create fractional part.
PaddedFractionStr = pad_right(FractionStr, '0', Prec + 1),
- ExpFractionStr = string.substring(PaddedFractionStr, DecimalPos,
- Prec + 1)
+ ExpFractionStr = string.between(PaddedFractionStr, DecimalPos,
+ DecimalPos + Prec + 1)
; Place > 0 ->
- ExpMantissaStr = string.substring(MantissaStr, 0, 1),
- FirstHalfOfFractionStr = string.substring(MantissaStr, 1, Place),
+ ExpMantissaStr = string.between(MantissaStr, 0, 1),
+ FirstHalfOfFractionStr = string.between(MantissaStr, 1, Place),
ExpFractionStr = FirstHalfOfFractionStr ++ FractionStr
;
ExpMantissaStr = MantissaStr,
@@ -3976,7 +4064,7 @@ change_precision(Prec, OldFloat) = NewFloat :-
PrecFracStr = string.pad_right(FractionStr, '0', Prec),
PrecMantissaStr = MantissaStr
; Prec < FracStrLen ->
- UnroundedFrac = string.substring(FractionStr, 0, Prec),
+ UnroundedFrac = string.between(FractionStr, 0, Prec),
NextDigit = string.det_index(FractionStr, Prec),
(
UnroundedFrac \= "",
@@ -3989,7 +4077,7 @@ change_precision(Prec, OldFloat) = NewFloat :-
string.count_codepoints(NewPrecFracStr) >
string.count_codepoints(UnroundedFrac)
->
- PrecFracStr = substring(NewPrecFracStr, 1, Prec),
+ PrecFracStr = between(NewPrecFracStr, 1, 1 + Prec),
PrecMantissaInt = det_to_int(MantissaStr) + 1,
PrecMantissaStr = int_to_string(PrecMantissaInt)
;
@@ -5348,16 +5436,14 @@ string.mercury_append(X, Y, Z) :-
/*-----------------------------------------------------------------------*/
-substring(Str, !.Start, !.Count, SubStr) :-
- ( !.Count =< 0 ->
+between(Str, Start, End, SubStr) :-
+ ( Start >= End ->
SubStr = ""
;
- % Be careful about integer overflow when Count = max_int.
Len = string.length(Str),
- max(0, !Start),
- min(Len, !Start),
- min(Len - !.Start, !Count),
- CharList = strchars(!.Start, !.Start + !.Count, Str),
+ max(0, Start, ClampStart),
+ min(Len, End, ClampEnd),
+ CharList = strchars(ClampStart, ClampEnd, Str),
SubStr = string.from_char_list(CharList)
).
@@ -5376,24 +5462,26 @@ strchars(I, End, Str) = Chars :-
).
:- pragma foreign_proc("C",
- string.substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness, may_not_duplicate, no_sharing],
"{
MR_Integer len;
+ MR_Integer Count;
MR_Word tmp;
if (Start < 0) Start = 0;
- if (Count <= 0) {
+ if (End <= Start) {
MR_make_aligned_string(SubString, """");
} else {
len = strlen(Str);
if (Start > len) {
Start = len;
}
- if (Count > len - Start) {
- Count = len - Start;
+ if (End > len) {
+ End = len;
}
+ Count = End - Start;
MR_allocate_aligned_string_msg(SubString, Count, MR_ALLOC_ID);
MR_memcpy(SubString, Str + Start, Count);
SubString[Count] = '\\0';
@@ -5401,117 +5489,143 @@ strchars(I, End, Str) = Chars :-
}").
:- pragma foreign_proc("C#",
- string.substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness, may_not_duplicate, no_sharing],
"
if (Start < 0) Start = 0;
- if (Count <= 0) {
+ if (End <= Start) {
SubString = """";
} else {
int len = Str.Length;
if (Start > len) {
Start = len;
}
- if (Count > len - Start) {
- Count = len - Start;
+ if (End > len) {
+ End = len;
}
- SubString = Str.Substring(Start, Count);
+ SubString = Str.Substring(Start, End - Start);
}
").
:- pragma foreign_proc("Java",
- string.substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness, may_not_duplicate, no_sharing],
"
if (Start < 0) Start = 0;
- if (Count <= 0) {
+ if (End <= Start) {
SubString = """";
} else {
int len = Str.length();
if (Start > len) {
Start = len;
}
- if (Count > len - Start) {
- Count = len - Start;
+ if (End > len) {
+ End = len;
}
- SubString = Str.substring(Start, Start + Count);
+ SubString = Str.substring(Start, End);
}
").
:- pragma foreign_proc("Erlang",
- string.substring(Str::in, Start0::in, Count0::in, SubString::uo),
+ string.between(Str::in, Start0::in, End0::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness],
"
- if Start0 < 0 ->
- Start = 0;
- true ->
- Start = Start0
- end,
- if
- Count0 =< 0 ->
- SubString = <<>>;
- Start > size(Str) ->
- SubString = <<>>;
- true ->
- if Count0 > size(Str) - Start ->
- Count = size(Str) - Start;
- true ->
- Count = Count0
- end,
- <<_:Start/binary, SubString:Count/binary, _/binary>> = Str
+ Start = max(Start0, 0),
+ End = min(End0, size(Str)),
+ Count = End - Start,
+ if Count =< 0 ->
+ SubString = <<>>
+ ; true ->
+ <<_:Start/binary, SubString:Count/binary, _/binary>> = Str
end
").
-string.substring_by_codepoint(Str, Start, Count) = SubString :-
- string.substring_by_codepoint(Str, Start, Count, SubString).
+string.between(Str, Start, End) = SubString :-
+ string.between(Str, Start, End, SubString).
-string.substring_by_codepoint(Str, Start, Count, SubString) :-
+string.substring(Str, Start, Count) = SubString :-
+ string.substring(Str, Start, Count, SubString).
+
+string.substring(Str, Start, Count, SubString) :-
+ convert_endpoints(Start, Count, ClampStart, ClampEnd),
+ string.between(Str, ClampStart, ClampEnd, SubString).
+
+:- pred convert_endpoints(int::in, int::in, int::out, int::out) is det.
+
+convert_endpoints(Start, Count, ClampStart, ClampEnd) :-
+ ClampStart = int.max(0, Start),
+ ( Count =< 0 ->
+ ClampEnd = ClampStart
+ ;
+ End = ClampStart + Count,
+ % Check for overflow.
+ ClampEnd = ( End =< 0 -> max_int ; End )
+ ).
+
+%-----------------------------------------------------------------------------%
+
+string.between_codepoints(Str, Start, End) = SubString :-
+ string.between_codepoints(Str, Start, End, SubString).
+
+string.between_codepoints(Str, Start, End, SubString) :-
( string.codepoint_offset(Str, Start, StartOffset0) ->
StartOffset = StartOffset0
;
StartOffset = 0
),
- ( string.codepoint_offset(Str, StartOffset, Count, EndOffset0) ->
+ ( string.codepoint_offset(Str, End, EndOffset0) ->
EndOffset = EndOffset0
;
EndOffset = string.length(Str)
),
- OffsetCount = EndOffset - StartOffset,
- string.substring(Str, StartOffset, OffsetCount, SubString).
+ string.between(Str, StartOffset, EndOffset, SubString).
:- pragma foreign_proc("C",
- string.unsafe_substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.unsafe_between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness, no_sharing],
"{
- MR_Integer len;
+ MR_Integer Count;
+ Count = End - Start;
MR_allocate_aligned_string_msg(SubString, Count, MR_ALLOC_ID);
MR_memcpy(SubString, Str + Start, Count);
SubString[Count] = '\\0';
}").
:- pragma foreign_proc("C#",
- string.unsafe_substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.unsafe_between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"{
- SubString = Str.Substring(Start, Count);
+ SubString = Str.Substring(Start, End - Start);
}").
:- pragma foreign_proc("Java",
- string.unsafe_substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.unsafe_between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- SubString = Str.substring(Start, Start + Count);
+ SubString = Str.substring(Start, End);
").
:- pragma foreign_proc("Erlang",
- string.unsafe_substring(Str::in, Start::in, Count::in, SubString::uo),
+ string.unsafe_between(Str::in, Start::in, End::in, SubString::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
+ Count = End - Start,
<< _:Start/binary, SubString:Count/binary, _/binary >> = Str
").
+string.unsafe_between(Str, Start, End) = SubString :-
+ string.unsafe_between(Str, Start, End, SubString).
+
+string.unsafe_substring(Str, Start, Count) = SubString :-
+ string.unsafe_between(Str, Start, Start + Count) = SubString.
+
+string.unsafe_substring(Str, Start, Count, SubString) :-
+ string.unsafe_between(Str, Start, Start + Count, SubString).
+
+%-----------------------------------------------------------------------------%
+
:- pragma foreign_proc("C",
string.split(Str::in, Count::in, Left::uo, Right::uo),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
@@ -6009,9 +6123,9 @@ string.foldl(F, S, A) = B :-
P = ( pred(X::in, Y::in, Z::out) is det :- Z = F(X, Y) ),
string.foldl(P, S, A, B).
-string.foldl_substring(F, S, Start, Count, A) = B :-
+string.foldl_between(F, S, Start, End, A) = B :-
P = ( pred(X::in, Y::in, Z::out) is det :- Z = F(X, Y) ),
- string.foldl_substring(P, S, Start, Count, A, B).
+ string.foldl_between(P, S, Start, End, A, B).
string.left(S1, N) = S2 :-
string.left(S1, N, S2).
@@ -6019,12 +6133,6 @@ string.left(S1, N) = S2 :-
string.right(S1, N) = S2 :-
string.right(S1, N, S2).
-string.substring(S1, N1, N2) = S2 :-
- string.substring(S1, N1, N2, S2).
-
-string.unsafe_substring(S1, N1, N2) = S2 :-
- string.unsafe_substring(S1, N1, N2, S2).
-
string.format(S1, PT) = S2 :-
string.format(S1, PT, S2).
@@ -6042,7 +6150,7 @@ words_2(SepP, String, WordStart, Words) :-
( WordEnd = WordStart ->
Words = []
;
- string.unsafe_substring(String, WordStart, WordEnd - WordStart, Word),
+ string.unsafe_between(String, WordStart, WordEnd, Word),
next_boundary(SepP, String, WordEnd, NextWordStart),
( WordEnd = NextWordStart ->
Words = [Word]
@@ -6091,7 +6199,7 @@ split_at_separator_2(DelimP, Str, I, SegEnd, Acc0, Acc) :-
( DelimP(C) ->
% Chop here.
SegStart = I,
- Seg = string.unsafe_substring(Str, SegStart, SegEnd - SegStart),
+ Seg = string.unsafe_between(Str, SegStart, SegEnd),
split_at_separator_2(DelimP, Str, J, J, [Seg | Acc0], Acc)
;
% Extend current segment.
@@ -6099,7 +6207,7 @@ split_at_separator_2(DelimP, Str, I, SegEnd, Acc0, Acc) :-
)
;
% We've reached the beginning of the string.
- Seg = string.unsafe_substring(Str, 0, SegEnd),
+ Seg = string.unsafe_between(Str, 0, SegEnd),
Acc = [Seg | Acc0]
).
@@ -6117,7 +6225,7 @@ split_at_string(Needle, Total) =
split_at_string(StartAt, NeedleLen, Needle, Total) = Out :-
( sub_string_search_start(Total, Needle, StartAt, NeedlePos) ->
- BeforeNeedle = substring(Total, StartAt, NeedlePos - StartAt),
+ BeforeNeedle = between(Total, StartAt, NeedlePos),
Tail = split_at_string(NeedlePos+NeedleLen, NeedleLen, Needle, Total),
Out = [BeforeNeedle | Tail]
;
@@ -6164,7 +6272,7 @@ lstrip(S) = lstrip_pred(is_whitespace, S).
strip(S0) = S :-
L = prefix_length(is_whitespace, S0),
R = suffix_length(is_whitespace, S0),
- S = substring(S0, L, length(S0) - L - R).
+ S = between(S0, L, length(S0) - R).
%-----------------------------------------------------------------------------%
diff --git a/mdbcomp/trace_counts.m b/mdbcomp/trace_counts.m
index bba6938..163bdec 100644
--- a/mdbcomp/trace_counts.m
+++ b/mdbcomp/trace_counts.m
@@ -710,7 +710,7 @@ string_to_goal_path(String) = Path :-
string.prefix(String, "<"),
string.suffix(String, ">"),
string.length(String, Length),
- string.substring(String, 1, Length-2, SubString),
+ string.between(String, 1, Length - 1, SubString),
rev_goal_path_from_string(SubString, Path).
% This function should be kept in sync with the MR_named_count_port array
diff --git a/profiler/demangle.m b/profiler/demangle.m
index cf68b1f..a5bc6bc 100644
--- a/profiler/demangle.m
+++ b/profiler/demangle.m
@@ -844,7 +844,7 @@ remove_maybe_module_prefix(MaybeModule, StringsToStopAt, String0, String) :-
string.left(String0, Index, Module),
string.length(String0, Len),
Index2 = Index + 2,
- string.substring(String0, Index2, Len, String1),
+ string.between(String0, Index2, Len, String1),
(
remove_maybe_module_prefix(yes(SubModule),
StringsToStopAt, String1, String2)
@@ -869,7 +869,7 @@ remove_maybe_pred_name(MaybePredName, String0, String) :-
string.left(String0, Index, PredName),
string.length(String0, Len),
Index2 = Index + 2,
- string.substring(String0, Index2, Len, String),
+ string.between(String0, Index2, Len, String),
MaybePredName = yes(PredName)
;
String = String0,
diff --git a/tests/general/Mercury.options b/tests/general/Mercury.options
index 744ffa9..613a916 100644
--- a/tests/general/Mercury.options
+++ b/tests/general/Mercury.options
@@ -9,6 +9,10 @@ MCFLAGS-mode_inference_reorder = --infer-all
MCFLAGS-intermod_type = --intermodule-optimization
MCFLAGS-intermod_type2 = --intermodule-optimization
+# These test cases also check obsolete procedures.
+MCFLAGS-string_foldl_substring = --no-warn-obsolete
+MCFLAGS-string_foldr_substring = --no-warn-obsolete
+
# In grade `none' with options `-O1 --opt-space' on kryten
# (a sparc-sun-solaris2.5 system), string_test needs to be linked
# with `--no-strip', otherwise it gets a seg fault.
diff --git a/tests/general/string_foldl_substring.exp b/tests/general/string_foldl_substring.exp
index 619ba98..1bec99d 100644
--- a/tests/general/string_foldl_substring.exp
+++ b/tests/general/string_foldl_substring.exp
@@ -4,4 +4,13 @@ rev("Hello, World!", 0, -5) = ""
rev("Hello, World!", -5, 12) = "dlroW ,olleH"
rev("Hello, World!", -5, 50) = "!dlroW ,olleH"
rev("Hello, World!", 7, 0) = ""
+rev("Hello, World!", 7, 12) = "dlroW"
rev("Hello, World!", 50, 10) = ""
+rev_old("Hello, World!", 0, 5) = "olleH"
+rev_old("Hello, World!", 0, 50) = "!dlroW ,olleH"
+rev_old("Hello, World!", 0, -5) = ""
+rev_old("Hello, World!", -5, 12) = "dlroW ,olleH"
+rev_old("Hello, World!", -5, 50) = "!dlroW ,olleH"
+rev_old("Hello, World!", 7, 0) = ""
+rev_old("Hello, World!", 7, 12) = "!dlroW"
+rev_old("Hello, World!", 50, 10) = ""
diff --git a/tests/general/string_foldl_substring.m b/tests/general/string_foldl_substring.m
index 2061a57..ad24895 100644
--- a/tests/general/string_foldl_substring.m
+++ b/tests/general/string_foldl_substring.m
@@ -39,14 +39,40 @@ main(!IO) :-
rev("Hello, World!", -5, 50),
"\"\nrev(\"Hello, World!\", 7, 0) = \"",
rev("Hello, World!", 7, 0),
+ "\"\nrev(\"Hello, World!\", 7, 12) = \"",
+ rev("Hello, World!", 7, 12),
"\"\nrev(\"Hello, World!\", 50, 10) = \"",
rev("Hello, World!", 50, 10),
"\"\n"
+ ], !IO),
+ io__write_strings([
+ "rev_old(\"Hello, World!\", 0, 5) = \"",
+ rev_old("Hello, World!", 0, 5),
+ "\"\nrev_old(\"Hello, World!\", 0, 50) = \"",
+ rev_old("Hello, World!", 0, 50),
+ "\"\nrev_old(\"Hello, World!\", 0, -5) = \"",
+ rev_old("Hello, World!", 0, -5),
+ "\"\nrev_old(\"Hello, World!\", -5, 12) = \"",
+ rev_old("Hello, World!", -5, 12),
+ "\"\nrev_old(\"Hello, World!\", -5, 50) = \"",
+ rev_old("Hello, World!", -5, 50),
+ "\"\nrev_old(\"Hello, World!\", 7, 0) = \"",
+ rev_old("Hello, World!", 7, 0),
+ "\"\nrev_old(\"Hello, World!\", 7, 12) = \"",
+ rev_old("Hello, World!", 7, 12),
+ "\"\nrev_old(\"Hello, World!\", 50, 10) = \"",
+ rev_old("Hello, World!", 50, 10),
+ "\"\n"
], !IO).
:- func rev(string, int, int) = string.
rev(S, I, N) =
+ from_char_list(foldl_between(func(X, Xs) = [X | Xs], S, I, N, [])).
+
+:- func rev_old(string, int, int) = string.
+
+rev_old(S, I, N) =
from_char_list(foldl_substring(func(X, Xs) = [X | Xs], S, I, N, [])).
%-----------------------------------------------------------------------------%
diff --git a/tests/general/string_foldr_substring.exp b/tests/general/string_foldr_substring.exp
index c3e0420..63cfeca 100644
--- a/tests/general/string_foldr_substring.exp
+++ b/tests/general/string_foldr_substring.exp
@@ -4,4 +4,13 @@ sub("Hello, World!", 0, -5) = ""
sub("Hello, World!", -5, 12) = "Hello, World"
sub("Hello, World!", -5, 50) = "Hello, World!"
sub("Hello, World!", 7, 0) = ""
+sub("Hello, World!", 7, 12) = "World"
sub("Hello, World!", 50, 10) = ""
+sub_old("Hello, World!", 0, 5) = "Hello"
+sub_old("Hello, World!", 0, 50) = "Hello, World!"
+sub_old("Hello, World!", 0, -5) = ""
+sub_old("Hello, World!", -5, 12) = "Hello, World"
+sub_old("Hello, World!", -5, 50) = "Hello, World!"
+sub_old("Hello, World!", 7, 0) = ""
+sub_old("Hello, World!", 7, 12) = "World!"
+sub_old("Hello, World!", 50, 10) = ""
diff --git a/tests/general/string_foldr_substring.m b/tests/general/string_foldr_substring.m
index 2f22d51..fdfcb38 100644
--- a/tests/general/string_foldr_substring.m
+++ b/tests/general/string_foldr_substring.m
@@ -39,14 +39,40 @@ main(!IO) :-
sub("Hello, World!", -5, 50),
"\"\nsub(\"Hello, World!\", 7, 0) = \"",
sub("Hello, World!", 7, 0),
+ "\"\nsub(\"Hello, World!\", 7, 12) = \"",
+ sub("Hello, World!", 7, 12),
"\"\nsub(\"Hello, World!\", 50, 10) = \"",
sub("Hello, World!", 50, 10),
"\"\n"
+ ], !IO),
+ io__write_strings([
+ "sub_old(\"Hello, World!\", 0, 5) = \"",
+ sub_old("Hello, World!", 0, 5),
+ "\"\nsub_old(\"Hello, World!\", 0, 50) = \"",
+ sub_old("Hello, World!", 0, 50),
+ "\"\nsub_old(\"Hello, World!\", 0, -5) = \"",
+ sub_old("Hello, World!", 0, -5),
+ "\"\nsub_old(\"Hello, World!\", -5, 12) = \"",
+ sub_old("Hello, World!", -5, 12),
+ "\"\nsub_old(\"Hello, World!\", -5, 50) = \"",
+ sub_old("Hello, World!", -5, 50),
+ "\"\nsub_old(\"Hello, World!\", 7, 0) = \"",
+ sub_old("Hello, World!", 7, 0),
+ "\"\nsub_old(\"Hello, World!\", 7, 12) = \"",
+ sub_old("Hello, World!", 7, 12),
+ "\"\nsub_old(\"Hello, World!\", 50, 10) = \"",
+ sub_old("Hello, World!", 50, 10),
+ "\"\n"
], !IO).
:- func sub(string, int, int) = string.
sub(S, I, N) =
+ from_char_list(foldr_between(func(X, Xs) = [X | Xs], S, I, N, [])).
+
+:- func sub_old(string, int, int) = string.
+
+sub_old(S, I, N) =
from_char_list(foldr_substring(func(X, Xs) = [X | Xs], S, I, N, [])).
%-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/Mercury.options b/tests/hard_coded/Mercury.options
index 08f34dc..cc52d39 100644
--- a/tests/hard_coded/Mercury.options
+++ b/tests/hard_coded/Mercury.options
@@ -50,6 +50,7 @@ MCFLAGS-opt_format = --optimize-format-calls
MCFLAGS-reuse_ho = --ctgc --no-optimise-higher-order
MCFLAGS-sharing_comb = --ctgc --structure-sharing-widening 2
MCFLAGS-simplify_multi_arm_switch = -O3
+MCFLAGS-string_substring = --no-warn-obsolete
MCFLAGS-uncond_reuse = --ctgc
MCFLAGS-uncond_reuse_bad = --ctgc
MCFLAGS-uo_regression1 = --from-ground-term-threshold=4
diff --git a/tests/hard_coded/string_codepoint.exp b/tests/hard_coded/string_codepoint.exp
index 42b96d5..82c494b 100644
--- a/tests/hard_coded/string_codepoint.exp
+++ b/tests/hard_coded/string_codepoint.exp
@@ -86,5 +86,5 @@ aĆĪ¾
right_by_codepoint:
åš.
-substring_by_codepoint:
+between_codepoints:
Ī¾å
diff --git a/tests/hard_coded/string_codepoint.exp2 b/tests/hard_coded/string_codepoint.exp2
index 4c30884..e2ef44e 100644
--- a/tests/hard_coded/string_codepoint.exp2
+++ b/tests/hard_coded/string_codepoint.exp2
@@ -86,5 +86,5 @@ aĆĪ¾
right_by_codepoint:
åš.
-substring_by_codepoint:
+between_codepoints:
Ī¾å
diff --git a/tests/hard_coded/string_codepoint.m b/tests/hard_coded/string_codepoint.m
index c9771fe..a9d3bce 100644
--- a/tests/hard_coded/string_codepoint.m
+++ b/tests/hard_coded/string_codepoint.m
@@ -99,8 +99,8 @@ main(!IO) :-
io.write_string(R3, !IO),
io.nl(!IO),
- io.write_string("\nsubstring_by_codepoint:\n", !IO),
- string.substring_by_codepoint(Str, 2, 2, Sub),
+ io.write_string("\nbetween_codepoints:\n", !IO),
+ string.between_codepoints(Str, 2, 4, Sub),
io.write_string(Sub, !IO),
io.nl(!IO).
diff --git a/tests/hard_coded/string_substring.m b/tests/hard_coded/string_substring.m
index 07e7bfe..93cf945 100644
--- a/tests/hard_coded/string_substring.m
+++ b/tests/hard_coded/string_substring.m
@@ -33,7 +33,24 @@ main(!IO) :-
string.substring("cat", 1, 0, ""),
string.substring("cat", 1, 1, "a"),
string.substring("cat", 1, 2, "at"),
- string.substring("cat", 1, 3, "at")
+ string.substring("cat", 1, 3, "at"),
+
+ string.between("cat", -1, max_int, "cat"),
+ string.between("cat", 0, max_int, "cat"),
+ string.between("cat", 1, max_int, "at"),
+ string.between("cat", 2, max_int, "t"),
+ string.between("cat", 3, max_int, ""),
+ string.between("cat", 4, max_int, ""),
+ string.between("cat", 0, 0, ""),
+ string.between("cat", 0, 1, "c"),
+ string.between("cat", 0, 2, "ca"),
+ string.between("cat", 0, 3, "cat"),
+ string.between("cat", 1, -1, ""),
+ string.between("cat", 1, 0, ""),
+ string.between("cat", 1, 1, ""),
+ string.between("cat", 1, 2, "a"),
+ string.between("cat", 1, 3, "at"),
+ string.between("cat", 1, 4, "at")
->
io.write_string("test succeeded\n", !IO)
;
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list