v / vlib / datatypes
Raw file | 341 loc (316 sloc) | 8.83 KB | Latest commit hash f16722596
1module datatypes
2
3struct DoublyListNode[T] {
4mut:
5 data T
6 next &DoublyListNode[T] = unsafe { 0 }
7 prev &DoublyListNode[T] = unsafe { 0 }
8}
9
10// DoublyLinkedList[T] represents a generic doubly linked list of elements, each of type T.
11pub struct DoublyLinkedList[T] {
12mut:
13 head &DoublyListNode[T] = unsafe { 0 }
14 tail &DoublyListNode[T] = unsafe { 0 }
15 // Internal iter pointer for allowing safe modification
16 // of the list while iterating. TODO: use an option
17 // instead of a pointer to determine it is initialized.
18 iter &DoublyListIter[T] = unsafe { 0 }
19 len int
20}
21
22// is_empty checks if the linked list is empty
23pub fn (list DoublyLinkedList[T]) is_empty() bool {
24 return list.len == 0
25}
26
27// len returns the length of the linked list
28pub fn (list DoublyLinkedList[T]) len() int {
29 return list.len
30}
31
32// first returns the first element of the linked list
33pub fn (list DoublyLinkedList[T]) first() !T {
34 if list.is_empty() {
35 return error('Linked list is empty')
36 }
37 return list.head.data
38}
39
40// last returns the last element of the linked list
41pub fn (list DoublyLinkedList[T]) last() !T {
42 if list.is_empty() {
43 return error('Linked list is empty')
44 }
45 return list.tail.data
46}
47
48// push_back adds an element to the end of the linked list
49pub fn (mut list DoublyLinkedList[T]) push_back(item T) {
50 mut new_node := &DoublyListNode[T]{
51 data: item
52 }
53 if list.is_empty() {
54 // first node case
55 list.head = new_node
56 list.tail = new_node
57 } else {
58 list.tail.next = new_node
59 new_node.prev = list.tail
60 list.tail = new_node
61 }
62 list.len += 1
63}
64
65// push_front adds an element to the beginning of the linked list
66pub fn (mut list DoublyLinkedList[T]) push_front(item T) {
67 mut new_node := &DoublyListNode[T]{
68 data: item
69 }
70 if list.is_empty() {
71 // first node case
72 list.head = new_node
73 list.tail = new_node
74 } else {
75 list.head.prev = new_node
76 new_node.next = list.head
77 list.head = new_node
78 }
79 list.len += 1
80}
81
82// pop_back removes the last element of the linked list
83pub fn (mut list DoublyLinkedList[T]) pop_back() !T {
84 if list.is_empty() {
85 return error('Linked list is empty')
86 }
87 defer {
88 list.len -= 1
89 }
90 if list.len == 1 {
91 // head == tail
92 value := list.tail.data
93 list.head = unsafe { nil }
94 list.tail = unsafe { nil }
95 return value
96 }
97 value := list.tail.data
98 list.tail.prev.next = unsafe { nil } // unlink tail
99 list.tail = list.tail.prev
100 return value
101}
102
103// pop_front removes the last element of the linked list
104pub fn (mut list DoublyLinkedList[T]) pop_front() !T {
105 if list.is_empty() {
106 return error('Linked list is empty')
107 }
108 defer {
109 list.len -= 1
110 }
111 if list.len == 1 {
112 // head == tail
113 value := list.head.data
114 list.head = unsafe { nil }
115 list.tail = unsafe { nil }
116 return value
117 }
118 value := list.head.data
119 list.head.next.prev = unsafe { nil } // unlink head
120 list.head = list.head.next
121 return value
122}
123
124// insert adds an element to the linked list at the given index
125pub fn (mut list DoublyLinkedList[T]) insert(idx int, item T) ! {
126 if idx < 0 || idx > list.len {
127 return error('Index ${idx} out of bounds [0..${list.len}]')
128 } else if idx == 0 {
129 // new head
130 list.push_front(item)
131 } else if idx == list.len {
132 // new tail
133 list.push_back(item)
134 } else if idx <= list.len / 2 {
135 list.insert_front(idx, item)
136 } else {
137 list.insert_back(idx, item)
138 }
139}
140
141// insert_back walks from the tail and inserts a new item at index idx
142// (determined from the forward index). This function should be called
143// when idx > list.len/2. This helper function assumes idx bounds have
144// already been checked and idx is not at the edges.
145fn (mut list DoublyLinkedList[T]) insert_back(idx int, item T) {
146 mut node := list.node(idx + 1)
147 mut prev := node.prev
148 // prev node
149 // ------ ------
150 // |next|---->|next|
151 // |prev|<----|prev|
152 // ------ ------
153 new := &DoublyListNode[T]{
154 data: item
155 next: node
156 prev: prev
157 }
158 // prev new node
159 // ------ ------ ------
160 // |next|---->|next|---->|next|
161 // |prev|<----|prev|<----|prev|
162 // ------ ------ ------
163 node.prev = new
164 prev.next = new
165 list.len += 1
166}
167
168// insert_front walks from the head and inserts a new item at index idx
169// (determined from the forward index). This function should be called
170// when idx <= list.len/2. This helper function assumes idx bounds have
171// already been checked and idx is not at the edges.
172fn (mut list DoublyLinkedList[T]) insert_front(idx int, item T) {
173 mut node := list.node(idx - 1)
174 mut next := node.next
175 // node next
176 // ------ ------
177 // |next|---->|next|
178 // |prev|<----|prev|
179 // ------ ------
180 new := &DoublyListNode[T]{
181 data: item
182 next: next
183 prev: node
184 }
185 // node new next
186 // ------ ------ ------
187 // |next|---->|next|---->|next|
188 // |prev|<----|prev|<----|prev|
189 // ------ ------ ------
190 node.next = new
191 next.prev = new
192 list.len += 1
193}
194
195// node walks from the head or tail and finds the node at index idx.
196// This helper function assumes the list is not empty and idx is in
197// bounds.
198fn (list &DoublyLinkedList[T]) node(idx int) &DoublyListNode[T] {
199 if idx <= list.len / 2 {
200 mut node := list.head
201 for h := 0; h < idx; h += 1 {
202 node = node.next
203 }
204 return node
205 }
206 mut node := list.tail
207 for t := list.len - 1; t >= idx; t -= 1 {
208 node = node.prev
209 }
210 return node
211}
212
213// index searches the linked list for item and returns the forward index
214// or none if not found.
215pub fn (list &DoublyLinkedList[T]) index(item T) !int {
216 mut hn := list.head
217 mut tn := list.tail
218 for h, t := 0, list.len - 1; h <= t; {
219 if hn.data == item {
220 return h
221 } else if tn.data == item {
222 return t
223 }
224 h += 1
225 hn = hn.next
226 t -= 1
227 tn = tn.prev
228 }
229 return error('none')
230}
231
232// delete removes index idx from the linked list and is safe to call
233// for any idx.
234pub fn (mut list DoublyLinkedList[T]) delete(idx int) {
235 if idx < 0 || idx >= list.len {
236 return
237 } else if idx == 0 {
238 list.pop_front() or {}
239 return
240 } else if idx == list.len - 1 {
241 list.pop_back() or {}
242 return
243 }
244 // node should be somewhere in the middle
245 mut node := list.node(idx)
246 node.prev.next = node.next
247 node.next.prev = node.prev
248 list.len -= 1
249}
250
251// str returns a string representation of the linked list
252pub fn (list DoublyLinkedList[T]) str() string {
253 return list.array().str()
254}
255
256// array returns a array representation of the linked list
257pub fn (list DoublyLinkedList[T]) array() []T {
258 mut result_array := []T{cap: list.len}
259 mut node := list.head
260 for unsafe { node != 0 } {
261 result_array << node.data
262 node = node.next
263 }
264 return result_array
265}
266
267// next implements the iter interface to use DoublyLinkedList with
268// V's `for x in list {` loop syntax.
269pub fn (mut list DoublyLinkedList[T]) next() ?T {
270 if list.iter == unsafe { nil } {
271 // initialize new iter object
272 list.iter = &DoublyListIter[T]{
273 node: list.head
274 }
275 return list.next()
276 }
277 if list.iter.node == unsafe { nil } {
278 list.iter = unsafe { nil }
279 return none
280 }
281 defer {
282 list.iter.node = list.iter.node.next
283 }
284 return list.iter.node.data
285}
286
287// iterator returns a new iterator instance for the `list`.
288pub fn (mut list DoublyLinkedList[T]) iterator() DoublyListIter[T] {
289 return DoublyListIter[T]{
290 node: list.head
291 }
292}
293
294// back_iterator returns a new backwards iterator instance for the `list`.
295pub fn (mut list DoublyLinkedList[T]) back_iterator() DoublyListIterBack[T] {
296 return DoublyListIterBack[T]{
297 node: list.tail
298 }
299}
300
301// DoublyListIter[T] is an iterator for DoublyLinkedList.
302// It starts from *the start* and moves forwards to *the end* of the list.
303// It can be used with V's `for x in iter {` construct.
304// One list can have multiple independent iterators, pointing to different positions/places in the list.
305// A DoublyListIter iterator instance always traverses the list from *start to finish*.
306pub struct DoublyListIter[T] {
307mut:
308 node &DoublyListNode[T] = unsafe { 0 }
309}
310
311// next returns *the next* element of the list, or `none` when the end of the list is reached.
312// It is called by V's `for x in iter{` on each iteration.
313pub fn (mut iter DoublyListIter[T]) next() ?T {
314 if iter.node == unsafe { nil } {
315 return none
316 }
317 res := iter.node.data
318 iter.node = iter.node.next
319 return res
320}
321
322// DoublyListIterBack[T] is an iterator for DoublyLinkedList.
323// It starts from *the end* and moves backwards to *the start* of the list.
324// It can be used with V's `for x in iter {` construct.
325// One list can have multiple independent iterators, pointing to different positions/places in the list.
326// A DoublyListIterBack iterator instance always traverses the list from *finish to start*.
327pub struct DoublyListIterBack[T] {
328mut:
329 node &DoublyListNode[T] = unsafe { 0 }
330}
331
332// next returns *the previous* element of the list, or `none` when the start of the list is reached.
333// It is called by V's `for x in iter{` on each iteration.
334pub fn (mut iter DoublyListIterBack[T]) next() ?T {
335 if iter.node == unsafe { nil } {
336 return none
337 }
338 res := iter.node.data
339 iter.node = iter.node.prev
340 return res
341}