mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
parent
cceaa73ff2
commit
6f66691214
@ -215,6 +215,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/fmt.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linked_list.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
|
@ -8,6 +8,7 @@ pub const empty_import = @import("empty.zig");
|
||||
pub const fmt = @import("fmt.zig");
|
||||
pub const hash_map = @import("hash_map.zig");
|
||||
pub const io = @import("io.zig");
|
||||
pub const linked_list = @import("linked_list.zig");
|
||||
pub const list = @import("list.zig");
|
||||
pub const math = @import("math.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
@ -28,6 +29,7 @@ test "std" {
|
||||
_ = @import("fmt.zig");
|
||||
_ = @import("hash_map.zig");
|
||||
_ = @import("io.zig");
|
||||
_ = @import("linked_list.zig");
|
||||
_ = @import("list.zig");
|
||||
_ = @import("math.zig");
|
||||
_ = @import("mem.zig");
|
||||
|
271
std/linked_list.zig
Normal file
271
std/linked_list.zig
Normal file
@ -0,0 +1,271 @@
|
||||
const debug = @import("debug.zig");
|
||||
const assert = debug.assert;
|
||||
const mem = @import("mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
/// Generic doubly linked list.
|
||||
pub fn LinkedList(comptime T: type) -> type {
|
||||
struct {
|
||||
const List = this;
|
||||
|
||||
/// Node inside the linked list wrapping the actual data.
|
||||
pub const Node = struct {
|
||||
prev: ?&Node,
|
||||
next: ?&Node,
|
||||
data: T,
|
||||
};
|
||||
|
||||
first: ?&Node,
|
||||
last: ?&Node,
|
||||
len: usize,
|
||||
allocator: &Allocator,
|
||||
|
||||
/// Initialize a linked list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// allocator: Dynamic memory allocator.
|
||||
///
|
||||
/// Returns:
|
||||
/// An empty linked list.
|
||||
pub fn init(allocator: &Allocator) -> List {
|
||||
List {
|
||||
.first = null,
|
||||
.last = null,
|
||||
.len = 0,
|
||||
.allocator = allocator,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a new node after an existing one.
|
||||
///
|
||||
/// Arguments:
|
||||
/// node: Pointer to a node in the list.
|
||||
/// new_node: Pointer to the new node to insert.
|
||||
pub fn insertAfter(list: &List, node: &Node, new_node: &Node) {
|
||||
new_node.prev = node;
|
||||
test (node.next) |next_node| {
|
||||
// Intermediate node.
|
||||
new_node.next = next_node;
|
||||
next_node.prev = new_node;
|
||||
} else {
|
||||
// Last element of the list.
|
||||
new_node.next = null;
|
||||
list.last = new_node;
|
||||
}
|
||||
node.next = new_node;
|
||||
|
||||
list.len += 1;
|
||||
}
|
||||
|
||||
/// Insert a new node before an existing one.
|
||||
///
|
||||
/// Arguments:
|
||||
/// node: Pointer to a node in the list.
|
||||
/// new_node: Pointer to the new node to insert.
|
||||
pub fn insertBefore(list: &List, node: &Node, new_node: &Node) {
|
||||
new_node.next = node;
|
||||
test (node.prev) |prev_node| {
|
||||
// Intermediate node.
|
||||
new_node.prev = prev_node;
|
||||
prev_node.next = new_node;
|
||||
} else {
|
||||
// First element of the list.
|
||||
new_node.prev = null;
|
||||
list.first = new_node;
|
||||
}
|
||||
node.prev = new_node;
|
||||
|
||||
list.len += 1;
|
||||
}
|
||||
|
||||
/// Insert a new node at the end of the list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// new_node: Pointer to the new node to insert.
|
||||
pub fn append(list: &List, new_node: &Node) {
|
||||
test (list.last) |last| {
|
||||
// Insert after last.
|
||||
list.insertAfter(last, new_node);
|
||||
} else {
|
||||
// Empty list.
|
||||
list.prepend(new_node);
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a new node at the beginning of the list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// new_node: Pointer to the new node to insert.
|
||||
pub fn prepend(list: &List, new_node: &Node) {
|
||||
test (list.first) |first| {
|
||||
// Insert before first.
|
||||
list.insertBefore(first, new_node);
|
||||
} else {
|
||||
// Empty list.
|
||||
list.first = new_node;
|
||||
list.last = new_node;
|
||||
new_node.prev = null;
|
||||
new_node.next = null;
|
||||
|
||||
list.len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a node from the list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// node: Pointer to the node to be removed.
|
||||
pub fn remove(list: &List, node: &Node) {
|
||||
test (node.prev) |prev_node| {
|
||||
// Intermediate node.
|
||||
prev_node.next = node.next;
|
||||
} else {
|
||||
// First element of the list.
|
||||
list.first = node.next;
|
||||
}
|
||||
|
||||
test (node.next) |next_node| {
|
||||
// Intermediate node.
|
||||
next_node.prev = node.prev;
|
||||
} else {
|
||||
// Last element of the list.
|
||||
list.last = node.prev;
|
||||
}
|
||||
|
||||
list.len -= 1;
|
||||
}
|
||||
|
||||
/// Remove and return the last node in the list.
|
||||
///
|
||||
/// Returns:
|
||||
/// A pointer to the last node in the list.
|
||||
pub fn pop(list: &List) -> ?&Node {
|
||||
const last = list.last ?? return null;
|
||||
list.remove(last);
|
||||
return last;
|
||||
}
|
||||
|
||||
/// Remove and return the first node in the list.
|
||||
///
|
||||
/// Returns:
|
||||
/// A pointer to the first node in the list.
|
||||
pub fn popFirst(list: &List) -> ?&Node {
|
||||
const first = list.first ?? return null;
|
||||
list.remove(first);
|
||||
return first;
|
||||
}
|
||||
|
||||
/// Allocate a new node.
|
||||
///
|
||||
/// Returns:
|
||||
/// A pointer to the new node.
|
||||
pub fn allocateNode(list: &List) -> %&Node {
|
||||
list.allocator.create(Node)
|
||||
}
|
||||
|
||||
/// Deallocate a node.
|
||||
///
|
||||
/// Arguments:
|
||||
/// node: Pointer to the node to deallocate.
|
||||
pub fn destroyNode(list: &List, node: &Node) {
|
||||
list.allocator.destroy(node);
|
||||
}
|
||||
|
||||
/// Allocate and initialize a node and its data.
|
||||
///
|
||||
/// Arguments:
|
||||
/// data: The data to put inside the node.
|
||||
///
|
||||
/// Returns:
|
||||
/// A pointer to the new node.
|
||||
pub fn createNode(list: &List, data: &const T) -> %&Node {
|
||||
var node = %return list.allocateNode();
|
||||
*node = Node {
|
||||
.prev = null,
|
||||
.next = null,
|
||||
.data = *data,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
/// Iterate through the elements of the list.
|
||||
///
|
||||
/// Returns:
|
||||
/// A list iterator with a next() method.
|
||||
pub fn iterate(list: &List) -> List.Iterator(false) {
|
||||
List.Iterator(false) {
|
||||
.node = list.first,
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate through the elements of the list backwards.
|
||||
///
|
||||
/// Returns:
|
||||
/// A list iterator with a next() method.
|
||||
pub fn iterateBackwards(list: &List) -> List.Iterator(true) {
|
||||
List.Iterator(true) {
|
||||
.node = list.last,
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract iteration over a linked list.
|
||||
pub fn Iterator(comptime backwards: bool) -> type {
|
||||
struct {
|
||||
const It = this;
|
||||
|
||||
node: ?&Node,
|
||||
|
||||
/// Return the next element of the list, until the end.
|
||||
/// When no more elements are available, return null.
|
||||
pub fn next(it: &It) -> ?&Node {
|
||||
const current = it.node ?? return null;
|
||||
it.node = if (backwards) current.prev else current.next;
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "basic linked list test" {
|
||||
var list = LinkedList(u32).init(&debug.global_allocator);
|
||||
|
||||
var one = %%list.createNode(1);
|
||||
var two = %%list.createNode(2);
|
||||
var three = %%list.createNode(3);
|
||||
var four = %%list.createNode(4);
|
||||
var five = %%list.createNode(5);
|
||||
defer {
|
||||
list.destroyNode(one);
|
||||
list.destroyNode(two);
|
||||
list.destroyNode(three);
|
||||
list.destroyNode(four);
|
||||
list.destroyNode(five);
|
||||
}
|
||||
|
||||
list.append(two); // {2}
|
||||
list.append(five); // {2, 5}
|
||||
list.prepend(one); // {1, 2, 5}
|
||||
list.insertBefore(five, four); // {1, 2, 4, 5}
|
||||
list.insertAfter(two, three); // {1, 2, 3, 4, 5}
|
||||
|
||||
// Traverse the list forwards and backwards.
|
||||
var it = list.iterate();
|
||||
var it_reverse = list.iterateBackwards();
|
||||
var index: u32 = 1;
|
||||
while (true) {
|
||||
const node = it.next() ?? break;
|
||||
const node_reverse = it_reverse.next() ?? break;
|
||||
assert (node.data == index);
|
||||
assert (node_reverse.data == (6 - index));
|
||||
index += 1;
|
||||
}
|
||||
|
||||
var first = list.popFirst(); // {2, 3, 4, 5}
|
||||
var last = list.pop(); // {2, 3, 4}
|
||||
list.remove(three); // {2, 4}
|
||||
|
||||
assert ((??list.first).data == 2);
|
||||
assert ((??list.last ).data == 4);
|
||||
assert (list.len == 2);
|
||||
}
|
Loading…
Reference in New Issue
Block a user