Skip to content

Commit 5915f85

Browse files
committed
optimize linkedlist
1 parent 2c3e278 commit 5915f85

File tree

2 files changed

+62
-50
lines changed

2 files changed

+62
-50
lines changed

vlib/datatypes/linked_list.v

+54-49
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,75 @@
11
module datatypes
22

3+
@[heap]
34
pub struct ListNode[T] {
45
mut:
56
data T
6-
next &ListNode[T] = unsafe { 0 }
7+
next &ListNode[T] = unsafe { nil }
78
}
89

10+
@[heap]
911
pub struct LinkedList[T] {
1012
mut:
11-
head &ListNode[T] = unsafe { 0 }
13+
head &ListNode[T] = unsafe { nil }
14+
tail &ListNode[T] = unsafe { nil }
1215
len int
1316
// Internal iter pointer for allowing safe modification
1417
// of the list while iterating. TODO: use an option
1518
// instead of a pointer to determine if it is initialized.
16-
iter &ListIter[T] = unsafe { 0 }
19+
iter &ListIter[T] = unsafe { nil }
1720
}
1821

1922
// is_empty checks if the linked list is empty
23+
@[inline]
2024
pub fn (list LinkedList[T]) is_empty() bool {
2125
return list.len == 0
2226
}
2327

2428
// len returns the length of the linked list
29+
@[inline]
2530
pub fn (list LinkedList[T]) len() int {
2631
return list.len
2732
}
2833

2934
// first returns the first element of the linked list
35+
@[inline]
3036
pub fn (list LinkedList[T]) first() !T {
3137
return if !list.is_empty() { list.head.data } else { error('Linked list is empty') }
3238
}
3339

3440
// last returns the last element of the linked list
41+
@[inline]
3542
pub fn (list LinkedList[T]) last() !T {
36-
if unsafe { list.head == 0 } {
37-
return error('Linked list is empty')
38-
} else {
39-
mut node := list.head
40-
for unsafe { node.next != 0 } {
41-
node = node.next
42-
}
43-
return node.data
44-
}
43+
return if !list.is_empty() { list.tail.data } else { error('Linked list is empty') }
4544
}
4645

4746
// index returns the element at the given index of the linked list
4847
pub fn (list LinkedList[T]) index(idx int) !T {
49-
if unsafe { list.head == 0 } {
48+
if list.is_empty() {
5049
return error('Linked list is empty')
51-
} else {
52-
mut node := list.head
53-
mut iterations := 0
54-
for unsafe { node.next != 0 } && iterations < idx {
55-
node = node.next
56-
iterations++
57-
}
58-
if iterations == idx {
59-
return node.data
60-
} else {
61-
return error('Index ${idx} != iterations: ${iterations}')
62-
}
6350
}
51+
if idx < 0 || idx >= list.len {
52+
return error('Index ${idx} out of bounds')
53+
}
54+
mut node := list.head
55+
for _ in 0 .. idx {
56+
node = node.next
57+
}
58+
return node.data
6459
}
6560

6661
// push adds an element to the end of the linked list
6762
pub fn (mut list LinkedList[T]) push(item T) {
6863
new_node := &ListNode[T]{
6964
data: item
7065
}
71-
if unsafe { list.head == 0 } {
66+
if list.is_empty() {
7267
// first node case
7368
list.head = new_node
7469
} else {
75-
mut node := list.head
76-
for unsafe { node.next != 0 } {
77-
node = node.next
78-
}
79-
node.next = new_node
70+
list.tail.next = new_node
8071
}
72+
list.tail = new_node
8173
list.len += 1
8274
}
8375

@@ -90,35 +82,40 @@ pub fn (mut list LinkedList[T]) push_many(elements []T) {
9082

9183
// pop removes the last element of the linked list
9284
pub fn (mut list LinkedList[T]) pop() !T {
93-
if unsafe { list.head == 0 } {
85+
if list.is_empty() {
9486
return error('Linked list is empty')
9587
}
9688
mut node := list.head
9789
mut to_return := unsafe { node.data }
98-
if unsafe { node.next == 0 } {
90+
if isnil(node.next) {
9991
// first node case
10092
// set to null
10193
list.head = unsafe { nil }
94+
list.tail = unsafe { nil }
10295
} else {
103-
for unsafe { node.next.next != 0 } {
96+
for !isnil(node.next.next) {
10497
node = node.next
10598
}
10699
to_return = unsafe { node.next.data }
107100
// set to null
108101
node.next = unsafe { nil }
102+
list.tail = node
109103
}
110104
list.len -= 1
111105
return to_return
112106
}
113107

114108
// shift removes the first element of the linked list
115109
pub fn (mut list LinkedList[T]) shift() !T {
116-
if unsafe { list.head == 0 } {
110+
if list.is_empty() {
117111
return error('Linked list is empty')
118112
} else {
119113
list.len -= 1
120114
node := list.head
121115
list.head = node.next
116+
if list.is_empty() {
117+
list.tail = unsafe { nil }
118+
}
122119
return node.data
123120
}
124121
}
@@ -127,28 +124,36 @@ pub fn (mut list LinkedList[T]) shift() !T {
127124
pub fn (mut list LinkedList[T]) insert(idx int, item T) ! {
128125
if idx < 0 || idx > list.len {
129126
return error('Index ${idx} out of bounds [0..${list.len}]')
130-
} else if list.len == 0 {
127+
}
128+
if idx == list.len {
131129
list.push(item)
130+
return
131+
}
132+
mut new_node := &ListNode[T]{
133+
data: item
134+
}
135+
if list.is_empty() {
136+
list.head = new_node
137+
list.tail = new_node
132138
} else {
133-
list.len += 1
134139
mut node := list.head
135140

136141
if idx == 0 {
137142
// first node case
138-
list.head = &ListNode[T]{
139-
data: item
140-
next: node
141-
}
143+
new_node.next = node
144+
list.head = new_node
142145
} else {
143146
for i := 0; i < idx - 1; i++ {
144147
node = node.next
145148
}
146-
node.next = &ListNode[T]{
147-
data: item
148-
next: node.next
149+
new_node.next = node.next
150+
node.next = new_node
151+
if isnil(new_node.next) {
152+
list.tail = new_node
149153
}
150154
}
151155
}
156+
list.len += 1
152157
}
153158

154159
// prepend adds an element to the beginning of the linked list (equivalent to insert(0, item))
@@ -165,7 +170,7 @@ pub fn (list LinkedList[T]) str() string {
165170
pub fn (list LinkedList[T]) array() []T {
166171
mut result_array := []T{cap: list.len}
167172
mut node := list.head
168-
for unsafe { node != 0 } {
173+
for !isnil(node) {
169174
result_array << node.data
170175
node = node.next
171176
}
@@ -175,14 +180,14 @@ pub fn (list LinkedList[T]) array() []T {
175180
// next implements the iteration interface to use LinkedList
176181
// with V's `for` loop syntax.
177182
pub fn (mut list LinkedList[T]) next() ?T {
178-
if list.iter == unsafe { nil } {
183+
if isnil(list.iter) {
179184
// initialize new iter object
180185
list.iter = &ListIter[T]{
181186
node: list.head
182187
}
183188
return list.next()
184189
}
185-
if list.iter.node == unsafe { nil } {
190+
if isnil(list.iter.node) {
186191
list.iter = unsafe { nil }
187192
return none
188193
}
@@ -205,13 +210,13 @@ pub fn (mut list LinkedList[T]) iterator() ListIter[T] {
205210
// An iterator instance always traverses the list from start to finish.
206211
pub struct ListIter[T] {
207212
mut:
208-
node &ListNode[T] = unsafe { 0 }
213+
node &ListNode[T] = unsafe { nil }
209214
}
210215

211216
// next returns the next element of the list, or `none` when the end of the list is reached.
212217
// It is called by V's `for x in iter{` on each iteration.
213218
pub fn (mut iter ListIter[T]) next() ?T {
214-
if iter.node == unsafe { nil } {
219+
if isnil(iter.node) {
215220
return none
216221
}
217222
res := unsafe { iter.node.data }

vlib/datatypes/linked_list_test.v

+8-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ fn test_push_many() {
3232
x := [1, 2, 3, 4, 5]
3333
list.push_many(x)
3434
assert list.first()! == 1
35-
assert list.first()! == 1
3635
list = LinkedList[int]{}
3736
list.first() or { return }
3837
assert false
@@ -41,6 +40,7 @@ fn test_push_many() {
4140
fn test_last() {
4241
mut list := LinkedList[int]{}
4342
list.push(1)
43+
assert list.first()! == 1
4444
assert list.last()! == 1
4545
list.push(2)
4646
assert list.last()! == 2
@@ -56,6 +56,7 @@ fn test_index() {
5656
list.push(2)
5757
assert list.index(1)! == 2
5858
list.pop()!
59+
assert list.index(0)! == 1
5960
list.index(1) or { return }
6061
assert false
6162
}
@@ -104,6 +105,11 @@ fn test_insert() {
104105
list.push(2)
105106
list.push(3)
106107
list.insert(1, 111) or { return }
108+
assert list.index(0)! == 1
109+
assert list.index(1)! == 111
110+
assert list.index(2)! == 2
111+
list.insert(4, 222) or { return }
112+
assert list.last()! == 222
107113
assert true
108114
}
109115

@@ -114,6 +120,7 @@ fn test_prepend() {
114120
list.push(3)
115121
list.prepend(111)
116122
assert list.first()! == 111
123+
assert list.index(1)! == 1
117124
}
118125

119126
fn test_str() {

0 commit comments

Comments
 (0)