Skip to content

lkqy/fast-cparse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

## 表达式变量、常量
以_, a~z 开头的token为变量

以A~Z 开头的token为函数

支持常量类型,比如1=>long, -1.0=>double, +2.0=>double

## 功能支持
1、+ - * / % ^(幂运算) 支持5种类型的数值类型及对应的数组类型

2、and or not

3、> >= == < <= != 支持四种类型的数值类型及对应的数组类型、string

4、in => vector, map, string(这个实现主要解决高性能场景下的动态求值,目前只支持特定类型的操作)

5、内置SET函数,用于初始化常量数组、集合

6、线程安全

7、不会触发异常

## 值类型
BoolValue

IntValue

LongValue

FloatValue

DoubleValue

StringValue

BoolArrayValue

IntArrayValue

LongArrayValue

FloatArrayValue

DoubleArrayValue

StringArrayValue


## 求值接口
eval_bool       => bool

eval_int        => int

eval_float      => float

eval_double     => double

eval_bools      => std::vector\<bool\>

eval_ints       => std::vector\<int\>

eval_floats     => std::vector\<float\>

eval_doubles    => std::vector\<double\>


## Example1: 最朴素的调用

```javascript
    Compile compile;
    auto env = compile.get("a < 7 and b < 4 and not c");
    ASSERT_TRUE(env->is_valid());
    env->add("a", 1);
    env->add("b", 2);
    env->add("c", 3);
    std::vecctor<bool> ret
    ASSERT_TRUE(env->eval(ret));
    ASSERT_FALSE(ret);
```
上述例子的耗时为:count=1百万时,耗时653毫秒

## Example2: 共享data

```javascript
    Compile compile;
    DataCollector dc;
    dc.add("a", 1);
    dc.add("b", 2);
    dc.add("c", 3);

    {
        auto env = compile.get("a < 7 and b < 4 and not c");
        ASSERT_TRUE(env->is_valid());
        env->add(dc);
        std::vecctor<bool> ret
        ASSERT_TRUE(env->eval(ret));
        ASSERT_FALSE(ret);
    }
    {
        auto env = compile.get("a < 7 or b < 4 or not c");
        ASSERT_TRUE(env->is_valid());
        env->add(dc);
        std::vecctor<bool> ret
        ASSERT_TRUE(env->eval(ret));
        ASSERT_TRUE(ret);
    }
```


## Example3: 变量按需获取

```javascript
    typedef std::function<Value*(const std::unordered_map<std::string, float>&, const std::string& name)> Func;
    Func f = [](const std::unordered_map<std::string, float>& m, const std::string& name) -> Value* {
        if (m.find(name) == m.end())
            return nullptr;
        return new FloatValue(m.at(name));
    };
    std::unordered_map<std::string, float> data = {
            {"a", 1.0f}, {"b", 2.0f}, {"c", 3.0f},
    };

    Compile compile;
    auto env = compile.get("a+b+c");
    env->set_data_func<std::unordered_map<std::string, float>>(f);
    env->add_data_source(data);
    float result = 0;
    ASSERT_TRUE(env->is_valid());
    ASSERT_TRUE(env->eval(result));
    ASSERT_EQ(result, 6.0f);
```


## 功能扩展
可以自定义函数,注册后,可以扩展表达式功能。目前支持的函数类型为参数为1个、 2个或者3个, 返回值为ValuePtr类型


## 瓶颈
目前的性能瓶颈是字符串查找、二叉树遍历。核心是cache missing率高


## 性能对比
比较场景:(a^b+c+d/e-f+(h^i+j*k-m+n)) * (1.0 + o *p ^ q /r+s+t)

测试方法:循环100万次

场景        耗时

parse       5.923秒

lua         1.842秒

parse向量版 0.358秒

ps: 编译1万次,耗时0.33秒,每一次编译33微秒

## ToDo

1) 检查内存缺页问题

2) 递归求值转换成循环

3) 集合要求强制类型,需要放开

4) 支持string +

5) 确认所有标量都已经添加

6) 函数参数类型提升

7) 自适应向量展开运算

8) 操作符类型不匹配时要报错

9) get时线程安全

## 说明

 1、env->add 指针时,不要直接写env->add("xx", &ctx); c++默认为bool类型


About

fast expression evaluation with c++

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages