mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
datatypes: add a forward iterator for LinkedList<T>, add forward and backward iterators for DoublyLinkedList<T>. Add tests for both.
This commit is contained in:
parent
a6576bec1d
commit
1f26e3fb1b
@ -7,6 +7,7 @@ mut:
|
||||
prev &DoublyListNode<T> = unsafe { 0 }
|
||||
}
|
||||
|
||||
// DoublyLinkedList<T> represents a generic doubly linked list of elements, each of type T.
|
||||
pub struct DoublyLinkedList<T> {
|
||||
mut:
|
||||
head &DoublyListNode<T> = unsafe { 0 }
|
||||
@ -254,7 +255,7 @@ pub fn (list DoublyLinkedList<T>) str() string {
|
||||
|
||||
// array returns a array representation of the linked list
|
||||
pub fn (list DoublyLinkedList<T>) array() []T {
|
||||
mut result_array := []T{}
|
||||
mut result_array := []T{cap: list.len}
|
||||
mut node := list.head
|
||||
for unsafe { node != 0 } {
|
||||
result_array << node.data
|
||||
@ -264,7 +265,7 @@ pub fn (list DoublyLinkedList<T>) array() []T {
|
||||
}
|
||||
|
||||
// next implements the iter interface to use DoublyLinkedList with
|
||||
// V's for loop syntax.
|
||||
// V's `for x in list {` loop syntax.
|
||||
pub fn (mut list DoublyLinkedList<T>) next() ?T {
|
||||
if list.iter == unsafe { nil } {
|
||||
// initialize new iter object
|
||||
@ -283,7 +284,58 @@ pub fn (mut list DoublyLinkedList<T>) next() ?T {
|
||||
return list.iter.node.data
|
||||
}
|
||||
|
||||
struct DoublyListIter<T> {
|
||||
// iterator returns a new iterator instance for the `list`.
|
||||
pub fn (mut list DoublyLinkedList<T>) iterator() DoublyListIter<T> {
|
||||
return DoublyListIter<T>{
|
||||
node: list.head
|
||||
}
|
||||
}
|
||||
|
||||
// back_iterator returns a new backwards iterator instance for the `list`.
|
||||
pub fn (mut list DoublyLinkedList<T>) back_iterator() DoublyListIterBack<T> {
|
||||
return DoublyListIterBack<T>{
|
||||
node: list.tail
|
||||
}
|
||||
}
|
||||
|
||||
// DoublyListIter<T> is an iterator for DoublyLinkedList.
|
||||
// It starts from *the start* and moves forwards to *the end* of the list.
|
||||
// It can be used with V's `for x in iter {` construct.
|
||||
// One list can have multiple independent iterators, pointing to different positions/places in the list.
|
||||
// A DoublyListIter iterator instance always traverses the list from *start to finish*.
|
||||
pub struct DoublyListIter<T> {
|
||||
mut:
|
||||
node &DoublyListNode<T> = unsafe { 0 }
|
||||
}
|
||||
|
||||
// next returns *the next* element of the list, or `none` when the end of the list is reached.
|
||||
// It is called by V's `for x in iter{` on each iteration.
|
||||
pub fn (mut iter DoublyListIter<T>) next() ?T {
|
||||
if iter.node == unsafe { nil } {
|
||||
return none
|
||||
}
|
||||
res := iter.node.data
|
||||
iter.node = iter.node.next
|
||||
return res
|
||||
}
|
||||
|
||||
// DoublyListIterBack<T> is an iterator for DoublyLinkedList.
|
||||
// It starts from *the end* and moves backwards to *the start* of the list.
|
||||
// It can be used with V's `for x in iter {` construct.
|
||||
// One list can have multiple independent iterators, pointing to different positions/places in the list.
|
||||
// A DoublyListIterBack iterator instance always traverses the list from *finish to start*.
|
||||
pub struct DoublyListIterBack<T> {
|
||||
mut:
|
||||
node &DoublyListNode<T> = unsafe { 0 }
|
||||
}
|
||||
|
||||
// next returns *the previous* element of the list, or `none` when the start of the list is reached.
|
||||
// It is called by V's `for x in iter{` on each iteration.
|
||||
pub fn (mut iter DoublyListIterBack<T>) next() ?T {
|
||||
if iter.node == unsafe { nil } {
|
||||
return none
|
||||
}
|
||||
res := iter.node.data
|
||||
iter.node = iter.node.prev
|
||||
return res
|
||||
}
|
||||
|
@ -166,3 +166,49 @@ fn test_array() ? {
|
||||
list.push_back(3)
|
||||
assert list.array() == [1, 2, 3]
|
||||
}
|
||||
|
||||
fn test_string_array() ? {
|
||||
mut list := DoublyLinkedList<[]string>{}
|
||||
list.push_back(['a'])
|
||||
list.push_back(['b'])
|
||||
list.push_back(['c'])
|
||||
assert list.array() == [['a'], ['b'], ['c']]
|
||||
}
|
||||
|
||||
fn test_iteration_with_for() ? {
|
||||
mut list := DoublyLinkedList<int>{}
|
||||
list.push_back(1)
|
||||
list.push_back(2)
|
||||
list.push_back(3)
|
||||
mut res := []int{}
|
||||
for x in list {
|
||||
res << x
|
||||
}
|
||||
assert res == [1, 2, 3]
|
||||
}
|
||||
|
||||
fn test_iterator() ? {
|
||||
mut list := DoublyLinkedList<int>{}
|
||||
list.push_back(1)
|
||||
list.push_back(2)
|
||||
list.push_back(3)
|
||||
mut iter := list.iterator()
|
||||
mut res := []int{}
|
||||
for x in iter {
|
||||
res << x
|
||||
}
|
||||
assert res == [1, 2, 3]
|
||||
}
|
||||
|
||||
fn test_back_iterator() ? {
|
||||
mut list := DoublyLinkedList<int>{}
|
||||
list.push_back(1)
|
||||
list.push_back(2)
|
||||
list.push_back(3)
|
||||
mut iter := list.back_iterator()
|
||||
mut res := []int{}
|
||||
for x in iter {
|
||||
res << x
|
||||
}
|
||||
assert res == [3, 2, 1]
|
||||
}
|
||||
|
@ -10,6 +10,10 @@ pub struct LinkedList<T> {
|
||||
mut:
|
||||
head &ListNode<T> = unsafe { 0 }
|
||||
len int
|
||||
// Internal iter pointer for allowing safe modification
|
||||
// of the list while iterating. TODO: use an option
|
||||
// instead of a pointer to determine if it is initialized.
|
||||
iter &ListIter<T> = unsafe { 0 }
|
||||
}
|
||||
|
||||
// is_empty checks if the linked list is empty
|
||||
@ -152,7 +156,7 @@ pub fn (list LinkedList<T>) str() string {
|
||||
|
||||
// array returns a array representation of the linked list
|
||||
pub fn (list LinkedList<T>) array() []T {
|
||||
mut result_array := []T{}
|
||||
mut result_array := []T{cap: list.len}
|
||||
mut node := list.head
|
||||
for unsafe { node != 0 } {
|
||||
result_array << node.data
|
||||
@ -160,3 +164,50 @@ pub fn (list LinkedList<T>) array() []T {
|
||||
}
|
||||
return result_array
|
||||
}
|
||||
|
||||
// next implements the iteration interface to use LinkedList
|
||||
// with V's `for` loop syntax.
|
||||
pub fn (mut list LinkedList<T>) next() ?T {
|
||||
if list.iter == unsafe { nil } {
|
||||
// initialize new iter object
|
||||
list.iter = &ListIter<T>{
|
||||
node: list.head
|
||||
}
|
||||
return list.next()
|
||||
}
|
||||
if list.iter.node == unsafe { nil } {
|
||||
list.iter = unsafe { nil }
|
||||
return none
|
||||
}
|
||||
defer {
|
||||
list.iter.node = list.iter.node.next
|
||||
}
|
||||
return list.iter.node.data
|
||||
}
|
||||
|
||||
// iterator returns a new iterator instance for the `list`.
|
||||
pub fn (mut list LinkedList<T>) iterator() ListIter<T> {
|
||||
return ListIter<T>{
|
||||
node: list.head
|
||||
}
|
||||
}
|
||||
|
||||
// ListIter<T> is an iterator for LinkedList.
|
||||
// It can be used with V's `for x in iter {` construct.
|
||||
// One list can have multiple independent iterators, pointing to different positions/places in the list.
|
||||
// An iterator instance always traverses the list from start to finish.
|
||||
pub struct ListIter<T> {
|
||||
mut:
|
||||
node &ListNode<T> = unsafe { 0 }
|
||||
}
|
||||
|
||||
// next returns the next element of the list, or `none` when the end of the list is reached.
|
||||
// It is called by V's `for x in iter{` on each iteration.
|
||||
pub fn (mut iter ListIter<T>) next() ?T {
|
||||
if iter.node == unsafe { nil } {
|
||||
return none
|
||||
}
|
||||
res := iter.node.data
|
||||
iter.node = iter.node.next
|
||||
return res
|
||||
}
|
||||
|
@ -120,3 +120,51 @@ fn test_array() ? {
|
||||
list.push(3)
|
||||
assert list.array() == [1, 2, 3]
|
||||
}
|
||||
|
||||
fn test_linked_list_iterating_with_for() ? {
|
||||
mut list := LinkedList<int>{}
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.push(3)
|
||||
mut res := []int{}
|
||||
for x in list {
|
||||
res << x
|
||||
}
|
||||
assert res == [1, 2, 3]
|
||||
}
|
||||
|
||||
fn test_linked_list_separate_iterators() ? {
|
||||
mut list := LinkedList<int>{}
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.push(3)
|
||||
mut it1 := list.iterator()
|
||||
mut it2 := list.iterator()
|
||||
mut it3 := list.iterator()
|
||||
assert it1.next()? == 1
|
||||
assert it1.next()? == 2
|
||||
assert it1.next()? == 3
|
||||
assert it2.next()? == 1
|
||||
if _ := it1.next() {
|
||||
assert false
|
||||
} else {
|
||||
assert true
|
||||
}
|
||||
if _ := it1.next() {
|
||||
assert false
|
||||
} else {
|
||||
assert true
|
||||
}
|
||||
assert it2.next()? == 2
|
||||
assert it2.next()? == 3
|
||||
if _ := it2.next() {
|
||||
assert false
|
||||
} else {
|
||||
assert true
|
||||
}
|
||||
mut res := []int{}
|
||||
for x in it3 {
|
||||
res << x
|
||||
}
|
||||
assert res == [1, 2, 3]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user