[m-rev.] for review: fix bug in string.split_at_separator

Peter Wang wangp at students.csse.unimelb.edu.au
Tue Jun 5 10:47:13 AEST 2007


Estimated hours taken: 1
Branches: main

library/string.m:
	Fix an off-by-one bug in string.split_at_separator.  The index in the
	initial call to split_at_separator2 was one past the end of the
	string, which worked in the C backends because strings are NUL
	terminated.

	Rename split_at_separator2 to split_at_separator_2 and make it more
	readable.

tests/hard_coded/string_split.exp:
tests/hard_coded/string_split.m:
	Add a couple of cases which seem more likely to fail with an incorrect
	implementation.

Index: library/string.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/string.m,v
retrieving revision 1.260
diff -u -r1.260 string.m
--- library/string.m	30 May 2007 08:16:08 -0000	1.260
+++ library/string.m	5 Jun 2007 00:36:19 -0000
@@ -4475,30 +4475,34 @@
 
 %------------------------------------------------------------------------------%
 
-string.split_at_separator(DelimPred, InStr) = OutStrs :-
-    Count = string.length(InStr),
-    split_at_separator2(DelimPred, InStr, Count, Count, [], OutStrs).
+string.split_at_separator(DelimP, String) = Substrings :-
+    Len = string.length(String),
+    split_at_separator_2(DelimP, String, Len - 1, Len, [], Substrings).
 
-:- pred split_at_separator2(pred(char)::in(pred(in) is semidet), string::in,
+:- pred split_at_separator_2(pred(char)::in(pred(in) is semidet), string::in,
     int::in, int::in, list(string)::in, list(string)::out) is det.
-split_at_separator2(DelimPred, Str, I, ThisSegEnd, ITail, OTail) :-
-    % Walk Str backwards extending accumulated list of chunks as chars
-    % matching DelimPred are found.
-    ( I < 0 -> % We're at the beginning.
-        ( ThisSegEnd<0 ->
-            OTail = ["" | ITail]
-        ;
-            ThisSeg = string.unsafe_substring(Str, 0, ThisSegEnd+1),
-            OTail = [ThisSeg | ITail]
-        )
+
+split_at_separator_2(DelimP, Str, I, SegEnd, Acc0, Acc) :-
+    % Walk Str backwards extending the accumulated list of chunks as chars
+    % matching DelimP are found.
+    %
+    % Invariant: -1 =< I < length(Str)
+    % SegEnd is one past the last index of the current segment.
+    %
+    ( I < 0 ->
+        % We've reached the beginning of the string.
+        Seg = string.unsafe_substring(Str, 0, SegEnd),
+        Acc = [Seg | Acc0]
     ;
         C = string.unsafe_index(Str, I),
-        ( DelimPred(C) -> % Chop here.
-            ThisSeg = string.unsafe_substring(Str, I+1, ThisSegEnd-I),
-            TTail = [ ThisSeg | ITail ],
-            split_at_separator2(DelimPred, Str, I-1, I-1, TTail, OTail)
-        ; % Extend current segment.
-            split_at_separator2(DelimPred, Str, I-1, ThisSegEnd, ITail, OTail)
+        ( DelimP(C) ->
+            % Chop here.
+            SegStart = I + 1,
+            Seg = string.unsafe_substring(Str, SegStart, SegEnd - SegStart),
+            split_at_separator_2(DelimP, Str, I - 1, I, [Seg | Acc0], Acc)
+        ;
+            % Extend current segment.
+            split_at_separator_2(DelimP, Str, I - 1, SegEnd, Acc0, Acc)
         )
     ).
 
Index: tests/hard_coded/string_split.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/string_split.exp,v
retrieving revision 1.1
diff -u -r1.1 string_split.exp
--- tests/hard_coded/string_split.exp	2 Feb 2007 05:39:58 -0000	1.1
+++ tests/hard_coded/string_split.exp	5 Jun 2007 00:36:19 -0000
@@ -1,3 +1,5 @@
+
+!
 hello:world:how:are:you!
 hello<tab>world<tab>how<tab>are<tab><tab>you!
 user<tab>group<tab>id1<tab>id2
Index: tests/hard_coded/string_split.m
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/string_split.m,v
retrieving revision 1.1
diff -u -r1.1 string_split.m
--- tests/hard_coded/string_split.m	2 Feb 2007 05:39:58 -0000	1.1
+++ tests/hard_coded/string_split.m	5 Jun 2007 00:36:19 -0000
@@ -10,6 +10,14 @@
 
 main(!IO) :-
   io__write_list(
+    split_at_separator(char__is_upper, ""),
+    ":", io__write_string, !IO),
+  io__nl(!IO),
+  io__write_list(
+    split_at_separator(char__is_upper, "!"),
+    ":", io__write_string, !IO),
+  io__nl(!IO),
+  io__write_list(
     split_at_separator(char__is_upper, "helloXworldXhowXareYyou!"),
     ":", io__write_string, !IO),
   io__nl(!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