A high-performance C++17 library for parsing and evaluating complex filter conditions at runtime. This library provides a flexible and type-safe way to evaluate expressions with arithmetic operations, comparisons, and logical operators on structured key-value data.
- Type-Safe Expressions: Supports multiple data types (int64_t, double, string, bool) with type checking
- Arithmetic Operations: Add, subtract, multiply, and divide operations
- Comparison Operations: Equality, inequality, greater than, less than, and their variants
- Logical Operations: AND, OR operations for combining multiple conditions
- Flexible API: Easy-to-use API for building complex filter conditions
- Exception Handling: Clear error messages for invalid operations and type mismatches
- Zero Dependencies: Core library has no external dependencies (tests and benchmarks use GoogleTest and Google Benchmark)
- C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
- CMake 3.10 or higher
- GoogleTest (optional, for testing)
- Google Benchmark (optional, for benchmarks)
mkdir build
cd build
cmake ..
make
You can customize the build with the following CMake options:
cmake -DBUILD_EXAMPLES=ON \ # Build example executables (default: ON)
-DBUILD_BENCHMARKS=ON \ # Build benchmarks (default: ON, requires Google Benchmark)
-DBUILD_TESTING=ON \ # Build tests (default: ON, requires GoogleTest)
..
Ubuntu/Debian:
sudo apt-get install libgtest-dev libbenchmark-dev
macOS (with Homebrew):
brew install googletest google-benchmark
#include "evaluator.h"
#include <iostream>
int main() {
// Create a filter condition: (A > 10) AND (B < 20)
FilterCondition condition = {
{
{ UnaryExpression{ComparisonOperations::GREATER_THAN, "A", int64_t(10)},
LogicalOperations::NONE },
{ UnaryExpression{ComparisonOperations::LESS_THAN, "B", int64_t(20)},
LogicalOperations::AND }
}
};
// Initialize evaluator with the condition
Evaluator evaluator;
evaluator.initialize(condition);
// Create key-value pairs to evaluate
std::vector<Key> keys = {
Key("A", int64_t(15)),
Key("B", int64_t(15))
};
// Evaluate the condition
bool result = evaluator.evaluate(keys);
std::cout << "Evaluation result: " << (result ? "true" : "false") << std::endl;
return 0;
}
// Create a condition: (A + B < 100) AND (C == "test")
FilterCondition condition = {
{
{ BinaryExpression{"A", ArithmeticOperations::ADD, "B",
ComparisonOperations::LESS_THAN, int64_t(100)},
LogicalOperations::NONE },
{ UnaryExpression{ComparisonOperations::EQUAL, "C", std::string("test")},
LogicalOperations::AND }
}
};
std::vector<Key> keys = {
Key("A", int64_t(30)),
Key("B", int64_t(40)),
Key("C", std::string("test"))
};
auto eval_fn = LanguageParser::parse(condition);
bool result = eval_fn(keys); // Returns true
Represents a key-value pair with a name and typed value.
class Key {
public:
Key(const std::string& name, const ValueType& value);
const std::string& getName() const;
const ValueType& getValue() const;
void setValue(const ValueType& value);
};
A variant type that can hold int64_t, double, string, or bool values.
using ValueType = std::variant<int64_t, double, std::string, bool>;
Static parser class that converts filter conditions into evaluable functions.
class LanguageParser {
public:
static std::function<bool(const std::vector<Key>&)> parse(const FilterCondition& condition);
};
Convenience wrapper around LanguageParser for easier usage.
class Evaluator {
public:
void initialize(const FilterCondition& condition);
bool evaluate(const std::vector<Key>& keys);
};
Simple comparison: key op value
struct UnaryExpression {
ComparisonOperations op;
std::string key;
ValueType value;
};
Arithmetic followed by comparison: (key1 arith_op key2) comp_op value
struct BinaryExpression {
std::string left_key;
ArithmeticOperations arith_op; // +, -, *, /
std::string right_key;
ComparisonOperations comp_op; // ==, !=, >, <, >=, <=
ValueType value;
};
ADD
- Addition (+)SUBTRACT
- Subtraction (-)MULTIPLY
- Multiplication (*)DIVIDE
- Division (/)
EQUAL
- Equality (==)NOT_EQUAL
- Inequality (!=)GREATER_THAN
- Greater than (>)LESS_THAN
- Less than (<)GREATER_EQUAL
- Greater than or equal (>=)LESS_EQUAL
- Less than or equal (<=)
AND
- Logical AND (&&)OR
- Logical OR (||)NONE
- No logical operation (for first expression)
The example/
directory contains working examples:
# Build and run examples
cd build
./basic
The project uses GoogleTest for unit testing. Tests are located in the test/
directory.
# Install GoogleTest first
sudo apt-get install libgtest-dev # Ubuntu/Debian
# Build with testing enabled
mkdir build && cd build
cmake -DBUILD_TESTING=ON ..
make
# Run tests
ctest
# or run individual test executables
./test_chatgpt
Performance benchmarks are available using Google Benchmark.
# Install Google Benchmark first
sudo apt-get install libbenchmark-dev # Ubuntu/Debian
# Build with benchmarks enabled
mkdir build && cd build
cmake -DBUILD_BENCHMARKS=ON ..
make
# Run benchmarks
./chatgpt
ExpressionEvaluator/
├── CMakeLists.txt # Main build configuration
├── LICENSE # GPL-3.0 license
├── README.md # This file
├── include/ # Public headers
│ ├── enums.h # Operation enumerations
│ ├── evaluator.h # High-level evaluator API
│ ├── filter_structs.h # Filter condition structures
│ ├── key.h # Key-value pair definition
│ └── parser.h # Core parser interface
├── src/ # Implementation files
│ └── parser.cpp # Parser implementation
├── example/ # Usage examples
│ └── basic.cpp # Basic usage example
├── test/ # Unit tests
│ └── test_chatgpt.cpp # Comprehensive test suite
└── benchmark/ # Performance benchmarks
├── CMakeLists.txt # Benchmark build config
└── chatgpt.cpp # Benchmark suite
The library throws ParseException
for various error conditions:
- Type Mismatch: Comparing values of different types
- Division by Zero: Arithmetic division by zero
- Key Not Found: Referenced key doesn't exist in the input
- Unsupported Operations: Invalid operation for a type (e.g., > on booleans)
Example:
try {
auto eval = LanguageParser::parse(condition);
bool result = eval(keys);
} catch (const ParseException& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
- The parser uses
std::variant
for type-safe value storage with minimal overhead - Filter conditions are compiled once and can be reused for multiple evaluations
- No dynamic memory allocation during evaluation (after initial parsing)
- Zero-copy semantics where possible
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit issues or pull requests.
- Follow the existing code style (C++17, consistent formatting)
- Add tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting
Project maintained by akr-25
- Built with modern C++17 features
- Uses GoogleTest for testing framework
- Uses Google Benchmark for performance testing
- 9 out of 9.11 words written in this repo is by AI.