The library is under development and subject to change. Contributions are welcome. You can also log an issue if you have a wish for enhancement or if you spot a bug.
#include <string>
#include <iostream>
#include <booleval/evaluator.hpp>
class foo
{
public:
foo( std::string value ) noexcept : value_{ std::move( value ) } {}
std::string const & value() const noexcept { return value_; }
private:
std::string value_{};
};
int main()
{
foo x{ "foo" };
foo y{ "bar" };
booleval::evaluator evaluator
{
booleval::make_field( "field", &foo::value )
};
if ( !evaluator.expression( "field eq foo" ) )
{
std::cerr << "Expression not valid!" << std::endl;
}
if ( evaluator.is_activated() )
{
std::cout << std::boolalpha << evaluator.evaluate( x ) << std::endl; // true
std::cout << std::boolalpha << evaluator.evaluate( y ) << std::endl; // false
}
return 0;
}
- Motivation
- Getting Started
- Benchmark
- Compilation
- Tests
- Compiler Compatibility
- Contributing
- License
- Support
booleval
is a header-only C++17 library for evaluating logical expressions. It implements recursive descent parser mechanism for building an expression tree for a user-defined logical expression. After the expression tree is being built, map of fields and values representing a certain object can be passed to the evaluator
component of this library which will evaluate those values to true
or false
according to the user-defined logical expression.
In programming languages like Java and C# accessing arbitrary fields inside a class represents an omnipresent problem. However, it got solved by introducing a reflections feature. This feature provides us information about the class to which a certain object belongs to and, also, the methods of that class which we can invoke at runtime.
Since the reflection feature is missing in C++, booleval
library is implemented. It checks whether the members of a class to which an object belongs to have certain values. Members of a class are specified in a string format and can be used to form a logical expression.
Providing an end-user a functionality of specifying a logical expression is a common way of filtering out a large amounts of objects. E.g. tcpdump
and BPF (Berkeley Packet Filter), network tools available on most UNIX-like operating systems, have pretty much the same syntax for their filter expression.
booleval
is a header-only C++17 library for evaluating logical expressions.
In order to improve performance, booleval
library does not copy objects that are being evaluated.
EQUAL TO operator is an optional operator. Therefore, logical expression that checks whether a field with the name field_a
has a value of foo
can be constructed in a two different ways:
- EQUAL TO operator is specified in the expression:
field_a eq foo
- EQUAL TO operator is not specified in the expression:
field_a foo
To conclude, equality operator is a default operator between two fields. Thus, it does not need to be specified in the logical expression.
(field_a foo and field_b bar) or field_a bar
(field_a eq foo and field_b eq bar) or field_a eq bar
(field_a foo and field_b bar
Note: Missing closing parenthesesfield_a foo bar
Note: Two field values in a row
Result of evaluation process contains two information:
success
:true
if evaluation process is successful; otherwise,false
message
: meaningful message if evaluation process is unsuccessful; otherwise, empty message
This kind of enriched lightweight result is being used instead of exceptions for performance reasons.
Examples of messages:
"Missing operand"
"Unknown field"
"Unknown token type"
Name | Keyword | Symbol |
---|---|---|
AND operator | AND / and | && |
OR operator | OR / or | | | |
EQUAL TO operator | EQ / eq | == |
NOT EQUAL TO operator | NEQ / neq | != |
GREATER THAN operator | GT / gt | > |
LESS THAN operator | LT / lt | < |
GREATER THAN OR EQUAL TO operator | GEQ / geq | >= |
LESS THAN OR EQUAL TO operator | LEQ / leq | <= |
LEFT parentheses | ∅ | ( |
RIGHT parentheses | ∅ | ) |
Following table shows benchmark results:
Benchmark | Time | Iterations |
---|---|---|
Building expression tree | 3817 ns | 180904 |
Evaluation | 1285 ns | 532522 |
In other words, it is possible to evaluate 2,413,045.84 objects per second.
In order to compile the library, run the following commands:
$ # create the build directory
$ mkdir build
$ cd build
$ # configure the project
$ cmake ../
$ # compile
$ make
In order to run unit tests, run the following commands:
$ # fetch the googletest submodule, needed for tests
$ git submodule init
$ git submodule update
$ mkdir build
$ cd build
$ # configure the project
$ cmake ..
$ # compile tests
$ make tests
$ # run tests
$ make test
- Clang/LLVM >= 7
- MSVC++ >= 19.16
- GCC >= 8.4
There are no 3rd party dependencies.
Feel free to contribute.
If you find that any of the tests fail, please create a ticket in the issue tracker indicating the following information:
- platform
- architecture
- library version
- minimal reproducible example
The project is available under the MIT license.
If you like the work booleval
library is doing, please consider supporting it: