array: optimized generic filter()

pull/2404/head
Alexander Medvednikov 2019-10-17 10:44:20 +03:00
parent eda0c73bef
commit 80e79a3966
6 changed files with 67 additions and 7 deletions

2
v.v
View File

@ -12,6 +12,8 @@ import (
fn main() {
// There's no `flags` module yet, so args have to be parsed manually
args := compiler.env_vflags_and_os_args()
//options := args.filter(it.starts_with('-'))
// Print the version and exit.
if '-v' in args || '--version' in args || 'version' in args {
version_hash := compiler.vhash()

View File

@ -332,7 +332,7 @@ pub fn (a []char) index(v char) int {
////////////// FILTER //////////////
// Creates a new array with all elements that pass the test implemented by the provided function.
pub fn (a []string) filter(predicate fn(p_val string, p_i int, p_arr []string) bool) []string
pub fn (a []string) filter2(predicate fn(p_val string, p_i int, p_arr []string) bool) []string
{
mut res := []string
for i := 0; i < a.len; i++ {
@ -343,7 +343,7 @@ pub fn (a []string) filter(predicate fn(p_val string, p_i int, p_arr []string)
return res
}
pub fn (a []int) filter(predicate fn(p_val, p_i int, p_arr []int) bool) []int
pub fn (a []int) filter2(predicate fn(p_val, p_i int, p_arr []int) bool) []int
{
mut res := []int
for i := 0; i < a.len; i++ {
@ -356,7 +356,7 @@ pub fn (a []int) filter(predicate fn(p_val, p_i int, p_arr []int) bool) []int
////////////// REDUCE //////////////
// Executes a reducer function (that you provide) on each element of the array,
// Executes a reducer function (that you provide) on each element of the array,
// resulting in a single output value.
pub fn (a []int) reduce(iter fn (accum, curr int) int, accum_start int) int {
mut _accum := 0

View File

@ -303,14 +303,14 @@ fn callback_2(val string, index int, arr []string) bool {
return val.len >= 2
}
fn test_filter() {
fn test_filter2() {
a := [1, 2, 3, 4, 5, 6]
b := a.filter(callback_1)
b := a.filter2(callback_1)
assert b[0] == 2
assert b[1] == 3
c := ['v', 'is', 'awesome']
d := c.filter(callback_2)
d := c.filter2(callback_2)
assert d[0] == 'is'
assert d[1] == 'awesome'
}
@ -338,3 +338,15 @@ fn test_reduce() {
assert f == -6
assert g == -7
}
fn test_filter() {
a := [1, 2, 3, 4, 5, 6]
b := a.filter(it % 2 == 0)
assert b[0] == 2
assert b[1] == 4
assert b[2] == 6
c := ['v', 'is', 'awesome']
d := c.filter(it.len > 1)
assert d[0] == 'is'
assert d[1] == 'awesome'
}

View File

@ -2104,6 +2104,50 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
return 'void'
}
field_name := p.lit
if field_name == 'filter' && str_typ.starts_with('array_') {
/*
// V
a := [1,2,3,4]
b := a.filter(it % 2 == 0)
// C
array_int a = ...;
array_int tmp2 = new_array(0, 4, 4);
for (int i = 0; i < a.len; i++) {
int it = ((int*)a.data)[i];
if (it % 2 == 0) array_push(&tmp2, &it);
}
array_int b = tmp2;
*/
val_type:=str_typ.right(6)
p.open_scope()
p.register_var(Var{
name: 'it'
typ: val_type
})
p.next()
p.check(.lpar)
p.cgen.resetln('')
tmp := p.get_tmp()
a := p.expr_var.name
p.cgen.set_placeholder(method_ph,'\n$str_typ $tmp = new_array(0, $a .len,sizeof($val_type));\n')
p.genln('for (int i = 0; i < ${a}.len; i++) {')
p.genln('$val_type it = (($val_type*)${a}.data)[i];')
if val_type == 'string'{
p.genln('println(it);')
}
p.gen('if (')
p.bool_expression()
p.genln(') array_push(&$tmp, &it);')
//p.genln(') array_push(&$tmp, &((($val_type*)${a}.data)[i]));')
//p.genln(') array_push(&$tmp, ${a}.data + i * ${a}.element_size);')
p.genln('}')
p.gen(tmp) // TODO why does this `gen()` work?
p.check(.rpar)
p.close_scope()
return str_typ
}
fname_tidx := p.cur_tok_index()
p.fgen(field_name)
//p.log('dot() field_name=$field_name typ=$str_typ')

View File

@ -93,6 +93,7 @@ enum TokenKind {
key_import_const
key_in
key_interface
//key_it
key_match
key_module
key_mut
@ -189,6 +190,7 @@ fn build_token_str() []string {
s[TokenKind.key_assert] = 'assert'
s[TokenKind.key_struct] = 'struct'
s[TokenKind.key_if] = 'if'
//s[TokenKind.key_it] = 'it'
s[TokenKind.key_else] = 'else'
s[TokenKind.key_return] = 'return'
s[TokenKind.key_module] = 'module'

View File

@ -153,7 +153,7 @@ pub fn v_test_v(args_before_test string){
//////////////////////////////////////////////////////////////
println('\nBuilding examples...')
mut es := new_test_sesion( args_before_test )
es.files << os.walk_ext(parent_dir+'/examples','.v').filter(stable_example)
es.files << os.walk_ext(parent_dir+'/examples','.v').filter2(stable_example)
es.test()
println( es.benchmark.total_message('building examples') )
//////////////////////////////////////////////////////////////