mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: support slices with negative indexes #[start..end] (gated arrays) (#12914)
This commit is contained in:
@@ -384,6 +384,57 @@ fn (a array) slice(start int, _end int) array {
|
||||
return res
|
||||
}
|
||||
|
||||
// slice_ni returns an array using the same buffer as original array
|
||||
// but starting from the `start` element and ending with the element before
|
||||
// the `end` element of the original array.
|
||||
// This function can use negative indexes `a.slice_ni(-3, a.len)`
|
||||
// that get the last 3 elements of the array otherwise it return an empty array.
|
||||
// This function always return a valid array.
|
||||
fn (a array) slice_ni(_start int, _end int) array {
|
||||
mut end := _end
|
||||
mut start := _start
|
||||
|
||||
if start < 0 {
|
||||
start = a.len + start
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
}
|
||||
|
||||
if end < 0 {
|
||||
end = a.len + end
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
}
|
||||
if end >= a.len {
|
||||
end = a.len
|
||||
}
|
||||
|
||||
if start >= a.len || start > end {
|
||||
res := array{
|
||||
element_size: a.element_size
|
||||
data: a.data
|
||||
offset: 0
|
||||
len: 0
|
||||
cap: 0
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
offset := start * a.element_size
|
||||
data := unsafe { &byte(a.data) + offset }
|
||||
l := end - start
|
||||
res := array{
|
||||
element_size: a.element_size
|
||||
data: data
|
||||
offset: a.offset + offset
|
||||
len: l
|
||||
cap: l
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// used internally for [2..4]
|
||||
fn (a array) slice2(start int, _end int, end_max bool) array {
|
||||
end := if end_max { a.len } else { _end }
|
||||
|
||||
78
vlib/builtin/gated_array_string_test.v
Normal file
78
vlib/builtin/gated_array_string_test.v
Normal file
@@ -0,0 +1,78 @@
|
||||
fn test_gated_arrays() {
|
||||
a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
assert a#[-1..] == [9]
|
||||
assert a#[..-9] == [0]
|
||||
assert a#[-9..-7] == [1, 2]
|
||||
assert a#[-2..] == [8, 9]
|
||||
|
||||
// fixed array
|
||||
a1 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]!
|
||||
assert a1#[-1..] == [9]
|
||||
assert a1#[..-9] == [0]
|
||||
assert a1#[-9..-7] == [1, 2]
|
||||
assert a1#[-2..] == [8, 9]
|
||||
|
||||
// empty array
|
||||
assert a#[-3..-4] == [] // start > end
|
||||
assert a#[20..] == [] // start > array.len
|
||||
assert a#[-20..-10] == [] // start+len < 0
|
||||
assert a#[20..-9] == [] // start > end && start > end
|
||||
}
|
||||
|
||||
fn test_gated_strings() {
|
||||
a := '0123456789'
|
||||
assert a#[-1..] == '9'
|
||||
assert a#[..-9] == '0'
|
||||
assert a#[-9..-7] == '12'
|
||||
assert a#[-2..] == '89'
|
||||
|
||||
// empty string
|
||||
assert a#[-3..-4] == '' // start > end
|
||||
assert a#[20..] == '' // start > array.len
|
||||
assert a#[-20..-10] == '' // start+len < 0
|
||||
assert a#[20..-9] == '' // start > end && start > end
|
||||
|
||||
//
|
||||
// test negative indexes in slices from github discussion
|
||||
//
|
||||
s := '0123456789'
|
||||
|
||||
// normal behaviour
|
||||
assert s#[1..3] == '12'
|
||||
assert s#[..3] == '012'
|
||||
assert s#[8..] == '89'
|
||||
|
||||
// negative indexes behaviour
|
||||
assert s#[-2..] == '89'
|
||||
assert s#[..-8] == '01'
|
||||
assert s#[2..-2] == '234567'
|
||||
assert s#[-12..-16] == ''
|
||||
assert s#[-8..-2] == '234567'
|
||||
|
||||
// out of bound both indexes
|
||||
assert s#[12..14] == ''
|
||||
assert s#[-12..16] == '0123456789'
|
||||
}
|
||||
|
||||
fn test_gated_mixed_strings() {
|
||||
//
|
||||
// test negative indexes in slices
|
||||
//
|
||||
a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
// normal behaviour
|
||||
assert a#[1..3].str() == '[1, 2]'
|
||||
assert a#[..3].str() == '[0, 1, 2]'
|
||||
assert a#[8..].str() == '[8, 9]'
|
||||
|
||||
// negative indexes behaviour
|
||||
assert a#[-2..].str() == '[8, 9]'
|
||||
assert a#[..-8].str() == '[0, 1]'
|
||||
assert a#[2..-2].str() == '[2, 3, 4, 5, 6, 7]'
|
||||
assert a#[-12..-16].str() == '[]'
|
||||
assert a#[-8..-2].str() == '[2, 3, 4, 5, 6, 7]'
|
||||
|
||||
// out of bound both indexes
|
||||
assert a#[12..14].str() == '[]'
|
||||
assert a#[-12..16].str() == a.str()
|
||||
}
|
||||
@@ -788,6 +788,60 @@ pub fn (s string) substr(start int, end int) string {
|
||||
return res
|
||||
}
|
||||
|
||||
// substr_ni returns the string between index positions `start` and `end` allowing negative indexes
|
||||
// This function always return a valid string.
|
||||
[direct_array_access]
|
||||
pub fn (s string) substr_ni(_start int, _end int) string {
|
||||
mut start := _start
|
||||
mut end := _end
|
||||
|
||||
// borders math
|
||||
if start < 0 {
|
||||
start = s.len + start
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
}
|
||||
|
||||
if end < 0 {
|
||||
end = s.len + end
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
}
|
||||
if end >= s.len {
|
||||
end = s.len
|
||||
}
|
||||
|
||||
if start > s.len || end < start {
|
||||
mut res := string{
|
||||
str: unsafe { malloc_noscan(1) }
|
||||
len: 0
|
||||
}
|
||||
unsafe {
|
||||
res.str[0] = 0
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
len := end - start
|
||||
|
||||
// string copy
|
||||
mut res := string{
|
||||
str: unsafe { malloc_noscan(len + 1) }
|
||||
len: len
|
||||
}
|
||||
for i in 0 .. len {
|
||||
unsafe {
|
||||
res.str[i] = s.str[start + i]
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
res.str[len] = 0
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// index returns the position of the first character of the input string.
|
||||
// It will return `-1` if the input string can't be found.
|
||||
[direct_array_access]
|
||||
|
||||
Reference in New Issue
Block a user