v / vlib / datatypes
Raw file | 213 loc (194 sloc) | 4.96 KB | Latest commit hash f16722596
1module datatypes
2
3pub struct ListNode[T] {
4mut:
5 data T
6 next &ListNode[T] = unsafe { 0 }
7}
8
9pub struct LinkedList[T] {
10mut:
11 head &ListNode[T] = unsafe { 0 }
12 len int
13 // Internal iter pointer for allowing safe modification
14 // of the list while iterating. TODO: use an option
15 // instead of a pointer to determine if it is initialized.
16 iter &ListIter[T] = unsafe { 0 }
17}
18
19// is_empty checks if the linked list is empty
20pub fn (list LinkedList[T]) is_empty() bool {
21 return list.len == 0
22}
23
24// len returns the length of the linked list
25pub fn (list LinkedList[T]) len() int {
26 return list.len
27}
28
29// first returns the first element of the linked list
30pub fn (list LinkedList[T]) first() !T {
31 return if !list.is_empty() { list.head.data } else { error('Linked list is empty') }
32}
33
34// last returns the last element of the linked list
35pub 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 }
45}
46
47// index returns the element at the given index of the linked list
48pub fn (list LinkedList[T]) index(idx int) !T {
49 if unsafe { list.head == 0 } {
50 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 }
63 }
64}
65
66// push adds an element to the end of the linked list
67pub fn (mut list LinkedList[T]) push(item T) {
68 new_node := &ListNode[T]{
69 data: item
70 }
71 if unsafe { list.head == 0 } {
72 // first node case
73 list.head = new_node
74 } else {
75 mut node := list.head
76 for unsafe { node.next != 0 } {
77 node = node.next
78 }
79 node.next = new_node
80 }
81 list.len += 1
82}
83
84// pop removes the last element of the linked list
85pub fn (mut list LinkedList[T]) pop() !T {
86 if unsafe { list.head == 0 } {
87 return error('Linked list is empty')
88 }
89 mut node := list.head
90 mut to_return := unsafe { node.data }
91 if unsafe { node.next == 0 } {
92 // first node case
93 // set to null
94 list.head = unsafe { nil }
95 } else {
96 for unsafe { node.next.next != 0 } {
97 node = node.next
98 }
99 to_return = unsafe { node.next.data }
100 // set to null
101 node.next = unsafe { nil }
102 }
103 list.len -= 1
104 return to_return
105}
106
107// shift removes the first element of the linked list
108pub fn (mut list LinkedList[T]) shift() !T {
109 if unsafe { list.head == 0 } {
110 return error('Linked list is empty')
111 } else {
112 list.len -= 1
113 node := list.head
114 list.head = node.next
115 return node.data
116 }
117}
118
119// insert adds an element to the linked list at the given index
120pub fn (mut list LinkedList[T]) insert(idx int, item T) ! {
121 if idx < 0 || idx > list.len {
122 return error('Index ${idx} out of bounds [0..${list.len}]')
123 } else if list.len == 0 {
124 list.push(item)
125 } else {
126 list.len += 1
127 mut node := list.head
128
129 if idx == 0 {
130 // first node case
131 list.head = &ListNode[T]{
132 data: item
133 next: node
134 }
135 } else {
136 for i := 0; i < idx - 1; i++ {
137 node = node.next
138 }
139 node.next = &ListNode[T]{
140 data: item
141 next: node.next
142 }
143 }
144 }
145}
146
147// prepend adds an element to the beginning of the linked list (equivalent to insert(0, item))
148pub fn (mut list LinkedList[T]) prepend(item T) {
149 list.insert(0, item) or {}
150}
151
152// str returns a string representation of the linked list
153pub fn (list LinkedList[T]) str() string {
154 return list.array().str()
155}
156
157// array returns a array representation of the linked list
158pub fn (list LinkedList[T]) array() []T {
159 mut result_array := []T{cap: list.len}
160 mut node := list.head
161 for unsafe { node != 0 } {
162 result_array << node.data
163 node = node.next
164 }
165 return result_array
166}
167
168// next implements the iteration interface to use LinkedList
169// with V's `for` loop syntax.
170pub fn (mut list LinkedList[T]) next() ?T {
171 if list.iter == unsafe { nil } {
172 // initialize new iter object
173 list.iter = &ListIter[T]{
174 node: list.head
175 }
176 return list.next()
177 }
178 if list.iter.node == unsafe { nil } {
179 list.iter = unsafe { nil }
180 return none
181 }
182 defer {
183 list.iter.node = list.iter.node.next
184 }
185 return list.iter.node.data
186}
187
188// iterator returns a new iterator instance for the `list`.
189pub fn (mut list LinkedList[T]) iterator() ListIter[T] {
190 return ListIter[T]{
191 node: list.head
192 }
193}
194
195// ListIter[T] is an iterator for LinkedList.
196// It can be used with V's `for x in iter {` construct.
197// One list can have multiple independent iterators, pointing to different positions/places in the list.
198// An iterator instance always traverses the list from start to finish.
199pub struct ListIter[T] {
200mut:
201 node &ListNode[T] = unsafe { 0 }
202}
203
204// next returns the next element of the list, or `none` when the end of the list is reached.
205// It is called by V's `for x in iter{` on each iteration.
206pub fn (mut iter ListIter[T]) next() ?T {
207 if iter.node == unsafe { nil } {
208 return none
209 }
210 res := unsafe { iter.node.data }
211 iter.node = iter.node.next
212 return res
213}