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 }
|
prev &DoublyListNode<T> = unsafe { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DoublyLinkedList<T> represents a generic doubly linked list of elements, each of type T.
|
||||||
pub struct DoublyLinkedList<T> {
|
pub struct DoublyLinkedList<T> {
|
||||||
mut:
|
mut:
|
||||||
head &DoublyListNode<T> = unsafe { 0 }
|
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
|
// array returns a array representation of the linked list
|
||||||
pub fn (list DoublyLinkedList<T>) array() []T {
|
pub fn (list DoublyLinkedList<T>) array() []T {
|
||||||
mut result_array := []T{}
|
mut result_array := []T{cap: list.len}
|
||||||
mut node := list.head
|
mut node := list.head
|
||||||
for unsafe { node != 0 } {
|
for unsafe { node != 0 } {
|
||||||
result_array << node.data
|
result_array << node.data
|
||||||
@ -264,7 +265,7 @@ pub fn (list DoublyLinkedList<T>) array() []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// next implements the iter interface to use DoublyLinkedList with
|
// 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 {
|
pub fn (mut list DoublyLinkedList<T>) next() ?T {
|
||||||
if list.iter == unsafe { nil } {
|
if list.iter == unsafe { nil } {
|
||||||
// initialize new iter object
|
// initialize new iter object
|
||||||
@ -283,7 +284,58 @@ pub fn (mut list DoublyLinkedList<T>) next() ?T {
|
|||||||
return list.iter.node.data
|
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:
|
mut:
|
||||||
node &DoublyListNode<T> = unsafe { 0 }
|
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)
|
list.push_back(3)
|
||||||
assert list.array() == [1, 2, 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:
|
mut:
|
||||||
head &ListNode<T> = unsafe { 0 }
|
head &ListNode<T> = unsafe { 0 }
|
||||||
len int
|
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
|
// 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
|
// array returns a array representation of the linked list
|
||||||
pub fn (list LinkedList<T>) array() []T {
|
pub fn (list LinkedList<T>) array() []T {
|
||||||
mut result_array := []T{}
|
mut result_array := []T{cap: list.len}
|
||||||
mut node := list.head
|
mut node := list.head
|
||||||
for unsafe { node != 0 } {
|
for unsafe { node != 0 } {
|
||||||
result_array << node.data
|
result_array << node.data
|
||||||
@ -160,3 +164,50 @@ pub fn (list LinkedList<T>) array() []T {
|
|||||||
}
|
}
|
||||||
return result_array
|
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)
|
list.push(3)
|
||||||
assert list.array() == [1, 2, 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