mirror of
https://github.com/vlang/v.git
synced 2025-08-04 02:07:28 -04:00
arrays: add reverse_iterator/1 + tests, allowing for for child in arrays.reverse_iterator(children) {
instead of explicit C for style loop; it also avoids allocations (#24755)
This commit is contained in:
parent
29188e9849
commit
f822792a10
37
vlib/arrays/reverse_iterator.v
Normal file
37
vlib/arrays/reverse_iterator.v
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
module arrays
|
||||||
|
|
||||||
|
// ReverseIterator provides a convenient way to iterate in reverse over all elements of an array,
|
||||||
|
// without making allocations, using this syntax: `for elem in arrays.reverse_iterator(a) {` .
|
||||||
|
pub struct ReverseIterator[T] {
|
||||||
|
mut:
|
||||||
|
a []T
|
||||||
|
i int
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse_iterator can be used to iterate over the elements in an array using this syntax:
|
||||||
|
// `for elem in arrays.reverse_iterator(a) {` .
|
||||||
|
pub fn reverse_iterator[T](a []T) ReverseIterator[T] {
|
||||||
|
return ReverseIterator[T]{
|
||||||
|
a: a
|
||||||
|
i: a.len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// next is the required method, to implement an iterator in V.
|
||||||
|
// It returns none when the iteration should stop.
|
||||||
|
// Otherwise it returns the current element of the array.
|
||||||
|
@[direct_array_access]
|
||||||
|
pub fn (mut iter ReverseIterator[T]) next() ?&T {
|
||||||
|
iter.i--
|
||||||
|
if iter.i < 0 {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
return unsafe { &iter.a[iter.i] }
|
||||||
|
}
|
||||||
|
|
||||||
|
// free frees the iterator resources.
|
||||||
|
pub fn (iter &ReverseIterator[T]) free() {
|
||||||
|
// The array stored in the iterator is not owned by the iterator.
|
||||||
|
// It should not be freed, when the iterator goes out of scope.
|
||||||
|
// This is the reason, that this manual free method exists and is empty.
|
||||||
|
}
|
89
vlib/arrays/reverse_iterator_test.v
Normal file
89
vlib/arrays/reverse_iterator_test.v
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import arrays
|
||||||
|
|
||||||
|
struct Compound {
|
||||||
|
mut:
|
||||||
|
s string
|
||||||
|
i int
|
||||||
|
u u64
|
||||||
|
m map[string]i16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check[T](original []T) {
|
||||||
|
mut result := []T{cap: original.len}
|
||||||
|
for x in arrays.reverse_iterator(original) {
|
||||||
|
result << x
|
||||||
|
}
|
||||||
|
assert result.len == original.len
|
||||||
|
assert result.first() == original.last()
|
||||||
|
assert result.reverse() == original
|
||||||
|
eprintln('> original: ${original}')
|
||||||
|
eprintln('> result: ${result}')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_reverse_iterator_basic() {
|
||||||
|
check(['abc', 'def', 'ghi', 'jkl'])
|
||||||
|
check([10, 20, 30, 40])
|
||||||
|
check([
|
||||||
|
Compound{'abc', 123, 444, {
|
||||||
|
'aa': i16(12)
|
||||||
|
'bb': 31
|
||||||
|
}},
|
||||||
|
Compound{'def', 456, 555, {
|
||||||
|
'bb': i16(22)
|
||||||
|
'cc': 32
|
||||||
|
}},
|
||||||
|
Compound{'xyz', 789, 666, {
|
||||||
|
'cc': i16(32)
|
||||||
|
'dd': 33
|
||||||
|
}},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_reverse_iterator_with_mut() {
|
||||||
|
mut original := [10, 20]
|
||||||
|
mut before := []int{cap: original.len}
|
||||||
|
mut after := []int{cap: original.len}
|
||||||
|
for mut x in arrays.reverse_iterator(original) {
|
||||||
|
before << *x
|
||||||
|
(**x)++
|
||||||
|
after << *x
|
||||||
|
}
|
||||||
|
assert before == [20, 10]
|
||||||
|
assert after == [21, 11]
|
||||||
|
assert original == [11, 21]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_reverse_iterator_with_mut_compound() {
|
||||||
|
mut original := [Compound{
|
||||||
|
s: 'abc'
|
||||||
|
i: 123
|
||||||
|
}, Compound{
|
||||||
|
s: 'xyz'
|
||||||
|
i: 987
|
||||||
|
}]
|
||||||
|
mut before := []Compound{cap: original.len}
|
||||||
|
mut after := []Compound{cap: original.len}
|
||||||
|
for mut x in arrays.reverse_iterator(original) {
|
||||||
|
before << *x
|
||||||
|
x.i++
|
||||||
|
x.s += ' tail'
|
||||||
|
x.u = 99
|
||||||
|
x.m['modified'] = 1
|
||||||
|
after << *x
|
||||||
|
}
|
||||||
|
assert after[0] == Compound{
|
||||||
|
s: 'xyz tail'
|
||||||
|
i: 988
|
||||||
|
u: 99
|
||||||
|
m: {
|
||||||
|
'modified': i16(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert before[0] == Compound{
|
||||||
|
s: 'xyz'
|
||||||
|
i: 987
|
||||||
|
u: 0
|
||||||
|
m: {}
|
||||||
|
}
|
||||||
|
assert after.reverse() == original
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user