authorgravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2017-05-03 20:28:06+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-03 14:28:06-04:00
log6f66691214a0709d913d15772e7b130ede7977c9
tree1a92aa32e355c3ff481c164190a80c664f573c2a
parentcceaa73ff26b042d0face50ed9798ef8db36deda

Generic doubly linked list. (#361)

Standard linked list

3 files changed, 274 insertions(+), 0 deletions(-)

CMakeLists.txt+1
......@@ -215,6 +215,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/fmt.zig" DESTINATION "${ZIG_STD_DEST}")
215215install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
216216install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
217217install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
218install(FILES "${CMAKE_SOURCE_DIR}/std/linked_list.zig" DESTINATION "${ZIG_STD_DEST}")
218219install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
219220install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
220221install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
std/index.zig+2
......@@ -8,6 +8,7 @@ pub const empty_import = @import("empty.zig");
88pub const fmt = @import("fmt.zig");
99pub const hash_map = @import("hash_map.zig");
1010pub const io = @import("io.zig");
11pub const linked_list = @import("linked_list.zig");
1112pub const list = @import("list.zig");
1213pub const math = @import("math.zig");
1314pub const mem = @import("mem.zig");
......@@ -28,6 +29,7 @@ test "std" {
2829 _ = @import("fmt.zig");
2930 _ = @import("hash_map.zig");
3031 _ = @import("io.zig");
32 _ = @import("linked_list.zig");
3133 _ = @import("list.zig");
3234 _ = @import("math.zig");
3335 _ = @import("mem.zig");
std/linked_list.zig created+271
......@@ -0,0 +1,271 @@
1const debug = @import("debug.zig");
2const assert = debug.assert;
3const mem = @import("mem.zig");
4const Allocator = mem.Allocator;
5
6/// Generic doubly linked list.
7pub fn LinkedList(comptime T: type) -> type {
8 struct {
9 const List = this;
10
11 /// Node inside the linked list wrapping the actual data.
12 pub const Node = struct {
13 prev: ?&Node,
14 next: ?&Node,
15 data: T,
16 };
17
18 first: ?&Node,
19 last: ?&Node,
20 len: usize,
21 allocator: &Allocator,
22
23 /// Initialize a linked list.
24 ///
25 /// Arguments:
26 /// allocator: Dynamic memory allocator.
27 ///
28 /// Returns:
29 /// An empty linked list.
30 pub fn init(allocator: &Allocator) -> List {
31 List {
32 .first = null,
33 .last = null,
34 .len = 0,
35 .allocator = allocator,
36 }
37 }
38
39 /// Insert a new node after an existing one.
40 ///
41 /// Arguments:
42 /// node: Pointer to a node in the list.
43 /// new_node: Pointer to the new node to insert.
44 pub fn insertAfter(list: &List, node: &Node, new_node: &Node) {
45 new_node.prev = node;
46 test (node.next) |next_node| {
47 // Intermediate node.
48 new_node.next = next_node;
49 next_node.prev = new_node;
50 } else {
51 // Last element of the list.
52 new_node.next = null;
53 list.last = new_node;
54 }
55 node.next = new_node;
56
57 list.len += 1;
58 }
59
60 /// Insert a new node before an existing one.
61 ///
62 /// Arguments:
63 /// node: Pointer to a node in the list.
64 /// new_node: Pointer to the new node to insert.
65 pub fn insertBefore(list: &List, node: &Node, new_node: &Node) {
66 new_node.next = node;
67 test (node.prev) |prev_node| {
68 // Intermediate node.
69 new_node.prev = prev_node;
70 prev_node.next = new_node;
71 } else {
72 // First element of the list.
73 new_node.prev = null;
74 list.first = new_node;
75 }
76 node.prev = new_node;
77
78 list.len += 1;
79 }
80
81 /// Insert a new node at the end of the list.
82 ///
83 /// Arguments:
84 /// new_node: Pointer to the new node to insert.
85 pub fn append(list: &List, new_node: &Node) {
86 test (list.last) |last| {
87 // Insert after last.
88 list.insertAfter(last, new_node);
89 } else {
90 // Empty list.
91 list.prepend(new_node);
92 }
93 }
94
95 /// Insert a new node at the beginning of the list.
96 ///
97 /// Arguments:
98 /// new_node: Pointer to the new node to insert.
99 pub fn prepend(list: &List, new_node: &Node) {
100 test (list.first) |first| {
101 // Insert before first.
102 list.insertBefore(first, new_node);
103 } else {
104 // Empty list.
105 list.first = new_node;
106 list.last = new_node;
107 new_node.prev = null;
108 new_node.next = null;
109
110 list.len = 1;
111 }
112 }
113
114 /// Remove a node from the list.
115 ///
116 /// Arguments:
117 /// node: Pointer to the node to be removed.
118 pub fn remove(list: &List, node: &Node) {
119 test (node.prev) |prev_node| {
120 // Intermediate node.
121 prev_node.next = node.next;
122 } else {
123 // First element of the list.
124 list.first = node.next;
125 }
126
127 test (node.next) |next_node| {
128 // Intermediate node.
129 next_node.prev = node.prev;
130 } else {
131 // Last element of the list.
132 list.last = node.prev;
133 }
134
135 list.len -= 1;
136 }
137
138 /// Remove and return the last node in the list.
139 ///
140 /// Returns:
141 /// A pointer to the last node in the list.
142 pub fn pop(list: &List) -> ?&Node {
143 const last = list.last ?? return null;
144 list.remove(last);
145 return last;
146 }
147
148 /// Remove and return the first node in the list.
149 ///
150 /// Returns:
151 /// A pointer to the first node in the list.
152 pub fn popFirst(list: &List) -> ?&Node {
153 const first = list.first ?? return null;
154 list.remove(first);
155 return first;
156 }
157
158 /// Allocate a new node.
159 ///
160 /// Returns:
161 /// A pointer to the new node.
162 pub fn allocateNode(list: &List) -> %&Node {
163 list.allocator.create(Node)
164 }
165
166 /// Deallocate a node.
167 ///
168 /// Arguments:
169 /// node: Pointer to the node to deallocate.
170 pub fn destroyNode(list: &List, node: &Node) {
171 list.allocator.destroy(node);
172 }
173
174 /// Allocate and initialize a node and its data.
175 ///
176 /// Arguments:
177 /// data: The data to put inside the node.
178 ///
179 /// Returns:
180 /// A pointer to the new node.
181 pub fn createNode(list: &List, data: &const T) -> %&Node {
182 var node = %return list.allocateNode();
183 *node = Node {
184 .prev = null,
185 .next = null,
186 .data = *data,
187 };
188 return node;
189 }
190
191 /// Iterate through the elements of the list.
192 ///
193 /// Returns:
194 /// A list iterator with a next() method.
195 pub fn iterate(list: &List) -> List.Iterator(false) {
196 List.Iterator(false) {
197 .node = list.first,
198 }
199 }
200
201 /// Iterate through the elements of the list backwards.
202 ///
203 /// Returns:
204 /// A list iterator with a next() method.
205 pub fn iterateBackwards(list: &List) -> List.Iterator(true) {
206 List.Iterator(true) {
207 .node = list.last,
208 }
209 }
210
211 /// Abstract iteration over a linked list.
212 pub fn Iterator(comptime backwards: bool) -> type {
213 struct {
214 const It = this;
215
216 node: ?&Node,
217
218 /// Return the next element of the list, until the end.
219 /// When no more elements are available, return null.
220 pub fn next(it: &It) -> ?&Node {
221 const current = it.node ?? return null;
222 it.node = if (backwards) current.prev else current.next;
223 return current;
224 }
225 }
226 }
227 }
228}
229
230test "basic linked list test" {
231 var list = LinkedList(u32).init(&debug.global_allocator);
232
233 var one = %%list.createNode(1);
234 var two = %%list.createNode(2);
235 var three = %%list.createNode(3);
236 var four = %%list.createNode(4);
237 var five = %%list.createNode(5);
238 defer {
239 list.destroyNode(one);
240 list.destroyNode(two);
241 list.destroyNode(three);
242 list.destroyNode(four);
243 list.destroyNode(five);
244 }
245
246 list.append(two); // {2}
247 list.append(five); // {2, 5}
248 list.prepend(one); // {1, 2, 5}
249 list.insertBefore(five, four); // {1, 2, 4, 5}
250 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
251
252 // Traverse the list forwards and backwards.
253 var it = list.iterate();
254 var it_reverse = list.iterateBackwards();
255 var index: u32 = 1;
256 while (true) {
257 const node = it.next() ?? break;
258 const node_reverse = it_reverse.next() ?? break;
259 assert (node.data == index);
260 assert (node_reverse.data == (6 - index));
261 index += 1;
262 }
263
264 var first = list.popFirst(); // {2, 3, 4, 5}
265 var last = list.pop(); // {2, 3, 4}
266 list.remove(three); // {2, 4}
267
268 assert ((??list.first).data == 2);
269 assert ((??list.last ).data == 4);
270 assert (list.len == 2);
271}