[m-rev.] for review: add more operations on cords
Julien Fischer
jfischer at opturion.com
Tue Jun 7 14:50:50 AEST 2022
For review by anyone.
--------------------
Add more operations on cords.
library/cord.m:
Add is_singleton/2, foldr2/6 and foldr3/8.
NEWS:
Announce the above additions.
tests/hard_coded/Mmakefile:
tests/hard_coded/test_cord3.{m,exp}:
Add a test of is_singleton/2 (and is_empty/1).
Julien.
diff --git a/NEWS b/NEWS
index 9e57774..539149e 100644
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,14 @@ Changes to the Mercury standard library
- func `promise_only_solution/1`
- pred `promise_only_solution_io/4`
+### Changes to the `cord` module
+
+* The following predicates have been added:
+
+ - pred `foldr2/6`
+ - pred `foldr3/8`
+ - pred `is_singleton/2`
+
### Changes to the `diet` module
* The following obsolete predicate has been removed:
diff --git a/library/cord.m b/library/cord.m
index b211e1c..d7307f3 100644
--- a/library/cord.m
+++ b/library/cord.m
@@ -2,7 +2,7 @@
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2002-2011 The University of Melbourne.
-% Copyright (C) 2013-2018 The Mercury team.
+% Copyright (C) 2013-2018, 2021-2022 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
@@ -58,6 +58,10 @@
%
:- func singleton(T) = cord(T).
+ % is_singleton(C, X) <=> list(C) = [X].
+ %
+:- pred is_singleton(cord(T)::in, T::out) is semidet.
+
% list(from_list(Xs)) = Xs
% An O(1) operation.
%
@@ -251,6 +255,42 @@
:- mode foldr_pred(in(pred(in, mdi, muo) is semidet), in, mdi, muo) is semidet.
:- mode foldr_pred(in(pred(in, di, uo) is semidet), in, di, uo) is semidet.
+ % foldr2(P, C, !AccA, !AccB):
+ %
+ % Equivalent to list.foldr2(P, list(C), !AccA, !AccB), but faster.
+ %
+:- pred foldr2(pred(T, A, A, B, B), cord(T), A, A, B, B).
+:- mode foldr2(in(pred(in, in, out, in, out) is det), in, in, out,
+ in, out) is det.
+:- mode foldr2(in(pred(in, in, out, mdi, muo) is det), in, in, out,
+ mdi, muo) is det.
+:- mode foldr2(in(pred(in, in, out, di, uo) is det), in, in, out,
+ di, uo) is det.
+:- mode foldr2(in(pred(in, in, out, in, out) is semidet), in, in, out,
+ in, out) is semidet.
+:- mode foldr2(in(pred(in, in, out, mdi, muo) is semidet), in, in, out,
+ mdi, muo) is semidet.
+:- mode foldr2(in(pred(in, in, out, di, uo) is semidet), in, in, out,
+ di, uo) is semidet.
+
+ % foldr3(P, C, !AccA, !AccB,! AccC):
+ %
+ % Equivalent to list.foldr3(P, list(C), !AccA, !AccB, !AccC), but faster.
+ %
+:- pred foldr3(pred(T, A, A, B, B, C, C), cord(T), A, A, B, B, C, C).
+:- mode foldr3(in(pred(in, in, out, in, out, in, out) is det), in,
+ in, out, in, out, in, out) is det.
+:- mode foldr3(in(pred(in, in, out, in, out, mdi, muo) is det), in,
+ in, out, in, out, mdi, muo) is det.
+:- mode foldr3(in(pred(in, in, out, in, out, di, uo) is det), in,
+ in, out, in, out, di, uo) is det.
+:- mode foldr3(in(pred(in, in, out, in, out, in, out) is semidet), in,
+ in, out, in, out, in, out) is semidet.
+:- mode foldr3(in(pred(in, in, out, in, out, mdi, muo) is semidet), in,
+ in, out, in, out, mdi, muo) is semidet.
+:- mode foldr3(in(pred(in, in, out, in, out, di, uo) is semidet), in,
+ in, out, in, out, di, uo) is semidet.
+
% map_foldl(P, CA, CB, !Acc):
%
% This predicate calls P on each element of the input cord, working
@@ -327,6 +367,13 @@ is_empty(empty_cord).
singleton(X) = nonempty_cord(unit_node(X)).
+is_singleton(C, X) :-
+ (
+ C = nonempty_cord(unit_node(X))
+ ;
+ C = nonempty_cord(list_node(X, []))
+ ).
+
%---------------------------------------------------------------------------%
from_list(Xs) = C :-
@@ -932,6 +979,78 @@ foldr_node_pred(P, C, Cs, !Acc) :-
foldr_node_pred(P, branch_node(A, B), Cs, !Acc) :-
foldr_node_pred(P, B, [A | Cs], !Acc).
+foldr2(_P, empty_cord, !Acc1, !Acc2).
+foldr2(P, nonempty_cord(N), !Acc1, !Acc2) :-
+ foldr2_node(P, N, [], !Acc1, !Acc2).
+
+:- pred foldr2_node(pred(T, A, A, B, B), cord_node(T), list(cord_node(T)),
+ A, A, B, B).
+:- mode foldr2_node(in(pred(in, in, out, in, out) is det), in, in,
+ in, out, in, out) is det.
+:- mode foldr2_node(in(pred(in, in, out, mdi, muo) is det), in, in,
+ in, out, mdi, muo) is det.
+:- mode foldr2_node(in(pred(in, in, out, di, uo) is det), in, in,
+ in, out, di, uo) is det.
+:- mode foldr2_node(in(pred(in, in, out, in, out) is semidet), in, in,
+ in, out, in, out) is semidet.
+:- mode foldr2_node(in(pred(in, in, out, mdi, muo) is semidet), in, in,
+ in, out, mdi, muo) is semidet.
+:- mode foldr2_node(in(pred(in, in, out, di, uo) is semidet), in, in,
+ in, out, di, uo) is semidet.
+
+foldr2_node(P, C, Cs, !Acc1, !Acc2) :-
+ (
+ C = unit_node(X),
+ P(X, !Acc1, !Acc2)
+ ;
+ C = list_node(H, T),
+ list.foldr2(P, [H | T], !Acc1, !Acc2)
+ ),
+ (
+ Cs = []
+ ;
+ Cs = [Y | Ys],
+ foldr2_node(P, Y, Ys, !Acc1, !Acc2)
+ ).
+foldr2_node(P, branch_node(A, B), Cs, !Acc1, !Acc2) :-
+ foldr2_node(P, B, [A | Cs], !Acc1, !Acc2).
+
+foldr3(_P, empty_cord, !Acc1, !Acc2, !Acc3).
+foldr3(P, nonempty_cord(N), !Acc1, !Acc2, !Acc3) :-
+ foldr3_node(P, N, [], !Acc1, !Acc2, !Acc3).
+
+:- pred foldr3_node(pred(T, A, A, B, B, C, C), cord_node(T),
+ list(cord_node(T)), A, A, B, B, C, C).
+:- mode foldr3_node(in(pred(in, in, out, in, out, in, out) is det), in,
+ in, in, out, in, out, in, out) is det.
+:- mode foldr3_node(in(pred(in, in, out, in, out, mdi, muo) is det), in,
+ in, in, out, in, out, mdi, muo) is det.
+:- mode foldr3_node(in(pred(in, in, out, in, out, di, uo) is det), in,
+ in, in, out, in, out, di, uo) is det.
+:- mode foldr3_node(in(pred(in, in, out, in, out, in, out) is semidet), in,
+ in, in, out, in, out, in, out) is semidet.
+:- mode foldr3_node(in(pred(in, in, out, in, out, mdi, muo) is semidet), in,
+ in, in, out, in, out, mdi, muo) is semidet.
+:- mode foldr3_node(in(pred(in, in, out, in, out, di, uo) is semidet), in,
+ in, in, out, in, out, di, uo) is semidet.
+
+foldr3_node(P, C, Cs, !Acc1, !Acc2, !Acc3) :-
+ (
+ C = unit_node(X),
+ P(X, !Acc1, !Acc2, !Acc3)
+ ;
+ C = list_node(H, T),
+ list.foldr3(P, [H | T], !Acc1, !Acc2, !Acc3)
+ ),
+ (
+ Cs = []
+ ;
+ Cs = [Y | Ys],
+ foldr3_node(P, Y, Ys, !Acc1, !Acc2, !Acc3)
+ ).
+foldr3_node(P, branch_node(A, B), Cs, !Acc1, !Acc2, !Acc3) :-
+ foldr3_node(P, B, [A | Cs], !Acc1, !Acc2, !Acc3).
+
%---------------------------------------------------------------------------%
map_foldl(_P, empty_cord, empty_cord, !A).
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index a67ae2f..89e2a60 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -430,6 +430,7 @@ ORDINARY_PROGS = \
test_char_digits \
test_cord \
test_cord2 \
+ test_cord3 \
test_imported_no_tag \
test_infinity \
test_int_hash \
diff --git a/tests/hard_coded/test_cord3.exp b/tests/hard_coded/test_cord3.exp
index e69de29..26cb216 100644
--- a/tests/hard_coded/test_cord3.exp
+++ b/tests/hard_coded/test_cord3.exp
@@ -0,0 +1,11 @@
+Empty is empty.
+Singleton1 is not empty.
+Singleton2 is not empty.
+NonSingleton1 is not empty.
+NonSingleton2 is not empty.
+
+Empty is not a singleton.
+Singleton1 is a singleton with element 1.
+Singleton2 is a singleton with element 2.
+NonSingleton1 is not a singleton.
+NonSingleton2 is not a singleton.
diff --git a/tests/hard_coded/test_cord3.m b/tests/hard_coded/test_cord3.m
index e69de29..c35a448 100644
--- a/tests/hard_coded/test_cord3.m
+++ b/tests/hard_coded/test_cord3.m
@@ -0,0 +1,63 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module test_cord3.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module cord.
+:- import_module list.
+:- import_module pair.
+:- import_module string.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+ list.foldl(test_is_empty, test_cords, !IO),
+ io.nl(!IO),
+ list.foldl(test_is_singleton, test_cords, !IO).
+
+%---------------------------------------------------------------------------%
+
+:- pred test_is_empty(pair(string, cord(int))::in, io::di, io::uo) is det.
+
+test_is_empty(Name - Cord, !IO) :-
+ Result = ( if cord.is_empty(Cord) then "empty" else "not empty" ),
+ io.format("%s is %s.\n", [s(Name), s(Result)], !IO).
+
+%---------------------------------------------------------------------------%
+
+:- pred test_is_singleton(pair(string, cord(int))::in, io::di, io::uo) is det.
+
+test_is_singleton(Name - Cord, !IO) :-
+ ( if cord.is_singleton(Cord, Result) then
+ io.format("%s is a singleton with element %d.\n",
+ [s(Name), i(Result)], !IO)
+ else
+ io.format("%s is not a singleton.\n", [s(Name)], !IO)
+ ).
+
+%---------------------------------------------------------------------------%
+
+:- func test_cords = list(pair(string, cord(int))).
+
+test_cords = [
+ "Empty" - cord.empty,
+ "Singleton1" - cord.singleton(1),
+ "Singleton2" - cord.from_list([2]),
+ "NonSingleton1" - cord.from_list([3, 4]),
+ "NonSingleton2" - (cord.singleton(5) ++ cord.singleton(6))
+].
+
+%---------------------------------------------------------------------------%
+:- end_module test_cord3.
+%---------------------------------------------------------------------------%
More information about the reviews
mailing list