Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / linked-list.sml
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8structure LinkedList: LINKED_LIST =
9struct
10
11structure Node =
12 struct
13 datatype 'a t = T of {elt: 'a,
14 next: 'a t option ref}
15
16 fun new elt = T {elt = elt,
17 next = ref NONE}
18
19 fun cons (elt, next) = T {elt = elt,
20 next = ref (SOME next)}
21
22 fun clearNext (T {next, ...}) = next := NONE
23 fun setNext (T {next, ...}, n) = next := SOME n
24
25 fun fold (n, ac, f) =
26 let
27 fun loop (T {elt, next}, ac) =
28 let
29 val ac = f (elt, ac)
30 in
31 case !next of
32 NONE => ac
33 | SOME n => loop (n, ac)
34 end
35 in
36 loop (n, ac)
37 end
38 end
39
40datatype 'a t = T of {first: 'a Node.t option ref,
41 last: 'a Node.t option ref}
42
43fun invariant (T {first, last}) =
44 case (!first, !last) of
45 (NONE, NONE) => true
46 | (SOME _, SOME (Node.T {next, ...})) => not (isSome (!next))
47 | _ => false
48
49fun fold (T {first, ...}, ac, f) =
50 case !first of
51 NONE => ac
52 | SOME n => Node.fold (n, ac, f)
53
54fun toList l = rev (fold (l, [], op ::))
55
56fun layout layoutX l = List.layout layoutX (toList l)
57
58fun empty () = T {first = ref NONE,
59 last = ref NONE}
60
61fun splice (T {first = f, last = l}, T {first = f', last = l'}): unit =
62 case (!l, !f') of
63 (NONE, NONE) => ()
64 | (NONE, _) => (f := !f'; l := !l')
65 | (_, NONE) => ()
66 | (SOME ln, SOME f'n) =>
67 (Node.setNext (ln, f'n)
68 ; l := !l')
69
70val ('a, 'b) unfoldr: 'a * ('a -> ('b * 'a) option) -> 'b t =
71 fn (a, f) =>
72 case f a of
73 NONE => empty ()
74 | SOME (b, a) =>
75 let
76 val last = Node.new b
77 fun loop (a: 'a, n: 'b Node.t): 'b Node.t =
78 case f a of
79 NONE => n
80 | SOME (b, a) => loop (a, Node.cons (b, n))
81 val first = loop (a, last)
82 in
83 T {first = ref (SOME first),
84 last = ref (SOME last)}
85 end
86
87val unfoldri: int * 'a * (int * 'a -> 'b * 'a) -> 'b t =
88 fn (n, a, f) =>
89 if n < 0
90 then Error.bug "LinkedList.unfoldri"
91 else
92 unfoldr ((n - 1, a), fn (i, a) =>
93 if i < 0
94 then NONE
95 else let
96 val (b, a) = f (i, a)
97 in
98 SOME (b, (i - 1, a))
99 end)
100
101val ('a, 'b) unfold: 'a * ('a -> ('b * 'a) option) -> 'b t =
102 fn (a, f) =>
103 case f a of
104 NONE => empty ()
105 | SOME (b, a) =>
106 let
107 val first = Node.new b
108 fun loop (a: 'a, n: 'b Node.t): 'b Node.t =
109 case f a of
110 NONE => n
111 | SOME (b, a) =>
112 let
113 val n' = Node.new b
114 val _ = Node.setNext (n, n')
115 in
116 loop (a, n')
117 end
118 val last = loop (a, first)
119 in
120 T {first = ref (SOME first),
121 last = ref (SOME last)}
122 end
123
124val unfoldi: int * 'a * (int * 'a -> 'b * 'a) -> 'b t =
125 fn (n, a, f) =>
126 if n < 0
127 then Error.bug "LinkedList.unfoldi"
128 else
129 unfold ((0, a), fn (i, a) =>
130 if i >= n
131 then NONE
132 else let
133 val (b, a') = f (i, a)
134 in
135 SOME (b, (i + 1, a'))
136 end)
137
138fun reverse (ll as T {first, last}) =
139 (if invariant ll
140 then ()
141 else Out.output (Out.error, "reverse 1\n")
142 ;
143 case !first of
144 NONE => ()
145 | SOME (n as Node.T {next, ...}) =>
146 case !next of
147 NONE => ()
148 | SOME n' =>
149 let
150 val _ = Node.clearNext n
151 fun loop (n, n' as Node.T {next, ...}) =
152 let
153 val no = !next
154 val _ = next := SOME n
155 in
156 case no of
157 NONE => ()
158 | SOME n'' => loop (n', n'')
159 end
160 val _ = loop (n, n')
161 val _ = Ref.swap (first, last)
162 in
163 ()
164 end
165 ; if invariant ll
166 then ()
167 else Out.output (Out.error, "reverse 2\n"))
168
169fun fromList l =
170 unfold (l,
171 fn [] => NONE
172 | x :: l => SOME (x, l))
173
174end