optimize `a in [1,2,3]` to `a == 1 || a == 2 || a == 3`

pull/2244/head
Alexander Medvednikov 2019-10-06 04:27:29 +03:00
parent 62133c6ffa
commit b242e8d7ff
4 changed files with 59 additions and 8 deletions

View File

@ -0,0 +1,40 @@
module main
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
// avoid allocation
// `typ` is the type of `a`
// `ph` is for string_eq()
fn (p mut Parser) in_optimization(typ string, ph int) {
p.check(.lsbr)
mut i := 0
// Get `a` expr value (can be a string literal, not a variable)
expr := p.cgen.cur_line.right(ph)
is_str := typ == 'string'
//println('!! $p.expr_var.name => $name ($typ)')
for p.tok != .rsbr && p.tok != .eof {
if i > 0 {
if is_str {
p.gen(' || string_eq($expr, ')
} else {
p.gen(' || $expr == ')
}
}
if i == 0 {
if is_str {
p.cgen.set_placeholder(ph, ' string_eq(')
p.gen(', ')
} else {
p.gen(' ==')
}
}
p.check_types(p.bool_expression(), typ)
if is_str {
p.gen(')')
}
if p.tok != .rsbr {
p.check(.comma)
}
i++
}
p.check(.rsbr)
}

View File

@ -1389,7 +1389,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
typ := expr_type.replace('Option_', '')
p.cgen.resetln(left + 'opt_ok($expr, sizeof($typ))')
}
else if expr_type[0]==`[` {
else if expr_type[0]==`[` {
// assignment to a fixed_array `mut a:=[3]int a=[1,2,3]!!`
expr := p.cgen.cur_line.right(pos).all_after('{').all_before('}')
left := p.cgen.cur_line.left(pos).all_before('=')
@ -1433,7 +1433,7 @@ fn (p mut Parser) var_decl() {
// first variable
names << p.check_name()
p.scanner.validate_var_name(names[0])
mut new_vars := 0
mut new_vars := 0
if names[0] != '_' && !p.known_var(names[0]) {
new_vars++
}
@ -2322,7 +2322,6 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
}
}
// TODO move this from index_expr()
// TODO if p.tok in ...
if (p.tok == .assign && !p.is_sql) || p.tok.is_assign() {
if is_indexer && is_str && !p.builtin_mod {
p.error('strings are immutable')
@ -2377,6 +2376,13 @@ fn (p mut Parser) indot_expr() string {
if p.tok == .key_in {
p.fgen(' ')
p.check(.key_in)
//if p.pref.is_debug && p.tok == .lsbr {
if p.tok == .lsbr {
// a in [1,2,3] optimization => `a == 1 || a == 2 || a == 3`
// avoids an allocation
p.in_optimization(typ, ph)
return 'bool'
}
p.fgen(' ')
p.gen('), ')
arr_typ := p.expression()

View File

@ -287,3 +287,12 @@ fn test_multi() {
//b := [ [[1,2,3],[4,5,6]], [[1,2]] ]
//assert b[0][0][0] == 1
}
fn test_in() {
a := [1,2,3]
assert 1 in a
assert 2 in a
assert 3 in a
assert !(4 in a)
assert !(0 in a)
}

View File

@ -629,12 +629,8 @@ pub fn (a []string) to_c() voidptr {
}
*/
fn is_space(c byte) bool {
return c in [` `,`\n`,`\t`,`\v`,`\f`,`\r`]
}
pub fn (c byte) is_space() bool {
return is_space(c)
return c in [` `,`\n`,`\t`,`\v`,`\f`,`\r`]
}
pub fn (s string) trim_space() string {