builtin: implement array.pop()

pull/5825/head
Delyan Angelov 2020-07-14 19:55:44 +03:00
parent de0b96f52c
commit cf7d03bda6
4 changed files with 50 additions and 4 deletions

View File

@ -256,6 +256,22 @@ pub fn (a array) last() voidptr {
}
}
// array.pop returns the last element of the array, and removes it
pub fn (mut a array) pop() voidptr {
// in a sense, this is the opposite of `a << x`
$if !no_bounds_checking? {
if a.len == 0 {
panic('array.pop: array is empty')
}
}
new_len := a.len - 1
last_elem := unsafe { byteptr(a.data) + (new_len) * a.element_size }
a.len = new_len
// NB: a.cap is not changed here *on purpose*, so that
// further << ops on that array will be more efficient.
return memdup(last_elem, a.element_size)
}
// array.slice 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 with the length and capacity

View File

@ -946,3 +946,29 @@ fn test_reverse_in_place() {
c.reverse_in_place()
assert c == [[5, 6], [3, 4], [1, 2]]
}
fn test_array_int_pop() {
mut a := [1,2,3,4,5]
assert a.len == 5
x := a.last()
y := a.pop()
assert x == y
assert a.len == 4
z := a.pop()
assert a.len == 3
assert z == 4
a.pop()
a.pop()
final := a.pop()
assert final == 1
}
fn test_array_string_pop() {
mut a := ['abc', 'def', 'xyz']
assert a.len == 3
assert a.pop() == 'xyz'
assert a.pop() == 'def'
assert a.pop() == 'abc'
assert a.len == 0
assert a.cap == 3
}

View File

@ -859,10 +859,14 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
call_expr.return_type = left_type
call_expr.receiver_type = left_type.to_ptr()
return call_expr.return_type
} else if left_type_sym.kind == .array && method_name in ['first', 'last'] {
} else if left_type_sym.kind == .array && method_name in ['first', 'last', 'pop'] {
info := left_type_sym.info as table.Array
call_expr.return_type = info.elem_type
call_expr.receiver_type = left_type
if method_name == 'pop' {
call_expr.receiver_type = left_type.to_ptr()
} else {
call_expr.receiver_type = left_type
}
return call_expr.return_type
} else if left_type_sym.kind == .array && method_name in ['insert', 'prepend'] {
array_info := left_type_sym.info as table.Array

View File

@ -352,12 +352,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
}
// TODO performance, detect `array` method differently
if left_sym.kind == .array && node.name in
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
receiver_type_name = 'array'
if node.name in ['last', 'first'] {
if node.name in ['last', 'first', 'pop'] {
return_type_str := g.typ(node.return_type)
g.write('*($return_type_str*)')
}