diff --git a/exprtk.hpp b/exprtk.hpp index fbe7622..ea93464 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -1619,6 +1619,7 @@ namespace exprtk e_in , e_like , e_ilike , + e_inranges , e_vov }; @@ -2672,6 +2673,18 @@ namespace exprtk static inline details::operator_type operation() { return details::e_ilike; } }; + template + struct inrange_op + { + static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } + static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) + { + return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); + } + static inline typename expression_node::node_type type() { return expression_node::e_inranges; } + static inline details::operator_type operation() { return details::e_ilike; } + }; + template class vov_base_node : public expression_node { @@ -2705,6 +2718,17 @@ namespace exprtk } }; + template + class sosos_base_node : public expression_node + { + public: + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + template class vov_node : public vov_base_node { @@ -3172,6 +3196,63 @@ namespace exprtk sos_node& operator=(sos_node&); }; + template + class sosos_node : public sosos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //variable op variable node + explicit sosos_node(SType0 s0, SType1 s1, SType2 s2) + : s0_(s0), + s1_(s1), + s2_(s2) + {} + + inline T value() const + { + return Operation::process(s0_,s1_,s2_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + inline std::string& s2() + { + return s2_; + } + + protected: + + SType0 s0_; + SType1 s1_; + SType2 s2_; + + private: + + sosos_node(sosos_node&); + sosos_node& operator=(sosos_node&); + }; + template inline bool is_vov_node(const expression_node* node) { @@ -3290,6 +3371,13 @@ namespace exprtk return new node_type(t1,t2,t3); } + template + inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const + { + return new node_type(t1,t2,t3); + } + template @@ -4305,6 +4393,19 @@ namespace exprtk return ((0 == expression_holder_) || (0 == expression_holder_->expr)); } + inline expression& release() + { + if (expression_holder_) + { + if (0 == --expression_holder_->ref_count) + { + delete expression_holder_; + } + expression_holder_ = 0; + } + return *this; + } + ~expression() { if (expression_holder_) @@ -5234,6 +5335,19 @@ namespace exprtk return false; } + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + bool b0_string = details::is_string_node(branch[0]) || details::is_const_string_node(branch[0]); + bool b1_string = details::is_string_node(branch[1]) || details::is_const_string_node(branch[1]); + bool b2_string = details::is_string_node(branch[2]) || details::is_const_string_node(branch[2]); + if ((b0_string || b1_string || b2_string) && !(b0_string && b1_string && b2_string)) + return true; + if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) + return true; + else + return false; + } + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { bool b0_string = details::is_string_node(branch[0]) || details::is_const_string_node(branch[0]); @@ -5241,6 +5355,14 @@ namespace exprtk return (b0_string && b1_string && valid_string_operation(operation)); } + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + bool b0_string = details::is_string_node(branch[0]) || details::is_const_string_node(branch[0]); + bool b1_string = details::is_string_node(branch[1]) || details::is_const_string_node(branch[1]); + bool b2_string = details::is_string_node(branch[2]) || details::is_const_string_node(branch[2]); + return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); + } + // Note: Extended Optimisations // When using older C++ compilers due to the large number of type instantiations // required by the extended optimisations the compiler may crash or not be able @@ -5303,7 +5425,14 @@ namespace exprtk inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { - return synthesize_expression(operation,branch); + if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) + return error_node(); + else if (is_invalid_string_op(operation,branch)) + return error_node(); + else if (is_string_operation(operation,branch)) + return synthesize_string_expression(operation,branch); + else + return synthesize_expression(operation,branch); } inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) @@ -5988,8 +6117,8 @@ namespace exprtk inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = dynamic_cast*>(branch[0])->str(); - std::string s1 = dynamic_cast*>(branch[1])->str(); + const std::string s0 = dynamic_cast*>(branch[0])->str(); + const std::string s1 = dynamic_cast*>(branch[1])->str(); expression_node_ptr result = error_node(); if (details::e_add == opr) result = node_allocator_->allocate_c >(s0 + s1); @@ -6033,6 +6162,101 @@ namespace exprtk } #endif + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) + { + if (details::e_inrange != opr) + return error_node(); + else if ( + details::is_const_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + const std::string s0 = dynamic_cast*>(branch[0])->str(); + const std::string s1 = dynamic_cast*>(branch[1])->str(); + const std::string s2 = dynamic_cast*>(branch[2])->str(); + Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + node_allocator_->free(branch[0]); + node_allocator_->free(branch[1]); + node_allocator_->free(branch[2]); + return node_allocator_->allocate_c >(v); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = dynamic_cast*>(branch[0])->ref(); + std::string& s1 = dynamic_cast*>(branch[1])->ref(); + std::string& s2 = dynamic_cast*>(branch[2])->ref(); + typedef typename details::sosos_node > inrange_t; + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string s0 = dynamic_cast*>(branch[0])->str(); + std::string& s1 = dynamic_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = dynamic_cast*>(branch[2])->str(); + typedef typename details::sosos_node > inrange_t; + node_allocator_->free(branch[0]); + node_allocator_->free(branch[2]); + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = dynamic_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = dynamic_cast*>(branch[1])->str(); + std::string& s2 = dynamic_cast< details::stringvar_node*>(branch[2])->ref(); + typedef typename details::sosos_node > inrange_t; + node_allocator_->free(branch[1]); + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string& s0 = dynamic_cast< details::stringvar_node*>(branch[0])->ref(); + std::string& s1 = dynamic_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = dynamic_cast*>(branch[2])->str(); + typedef typename details::sosos_node > inrange_t; + node_allocator_->free(branch[2]); + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details:: is_string_node(branch[1]) && + details:: is_string_node(branch[2]) + ) + { + std::string s0 = dynamic_cast*>(branch[0])->str(); + std::string& s1 = dynamic_cast< details::stringvar_node*>(branch[1])->ref(); + std::string& s2 = dynamic_cast< details::stringvar_node*>(branch[2])->ref(); + typedef typename details::sosos_node > inrange_t; + node_allocator_->free(branch[0]); + return node_allocator_->allocate_type(s0,s1,s2); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&)[3]) + { + return error_node(); + } + #endif + template inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) { diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 4bf379e..2a6f5d7 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -849,12 +849,14 @@ struct test_ab : expr(e), a(v0), b(v1), + c("ccc"), result(r) {} std::string expr; std::string a; std::string b; + std::string c; T result; }; @@ -880,6 +882,7 @@ inline bool run_test02() test_ab("'a123b' like '*123?'" ,"","",T(1.0)), test_ab("'1XYZ2' ilike '*xyz*'" ,"","",T(1.0)), test_ab("'1XYZ2' ilike '*xyz?'" ,"","",T(1.0)), + test_ab("inrange('aaa','bbb','ccc')" ,"","",T(1.0)), test_ab("a == b" ,"aaa","aaa",T(1.0)), test_ab("a != b" ,"aaa","bbb",T(1.0)), test_ab("a < b" ,"aaa","bbb",T(1.0)), @@ -913,6 +916,11 @@ inline bool run_test02() test_ab("a ilike '*xyz?'" ,"1XYZ2","",T(1.0)), test_ab("'1XYZ2' ilike b" ,"","*xyz*",T(1.0)), test_ab("'1XYZ2' ilike b" ,"","*xyz?",T(1.0)), + test_ab("inrange(a,'bbb',c)" ,"aaa","bbb",T(1.0)), + test_ab("inrange('aaa',b,'ccc')" ,"aaa","bbb",T(1.0)), + test_ab("inrange(a,b,c)" ,"aaa","bbb",T(1.0)), + test_ab("inrange(a,b,'ccc')" ,"aaa","bbb",T(1.0)), + test_ab("inrange('aaa',b,c)" ,"aaa","bbb",T(1.0)), }; @@ -928,6 +936,7 @@ inline bool run_test02() exprtk::symbol_table symbol_table; symbol_table.add_stringvar("a",test.a); symbol_table.add_stringvar("b",test.b); + symbol_table.add_stringvar("c",test.c); exprtk::expression expression; expression.register_symbol_table(symbol_table); @@ -1268,6 +1277,7 @@ inline bool run_test08() "(3min(x,y))==(3*min(x,y))", "(sin(x)y)==(sin(x)*y)", "(sin(x)cos(y)+1)==(sin(x)*cos(y)+1)", + "(sgn(sin(x))cos(sgn(y))+1)==(sgn(sin(x))*cos(sgn(y))+1)", "equal($f00(x,y,z),((x+y)/z))", "equal($f01(x,y,z),((x+y)*z))", "equal($f02(x,y,z),((x-y)/z))", @@ -1828,6 +1838,63 @@ inline bool run_test10() return true; } +template +inline bool run_test11() +{ + typedef exprtk::expression expression_t; + std::string expression_string = "(x + y) / 3"; + + T x = T(1.0); + T y = T(2.0); + + exprtk::symbol_table symbol_table; + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + static const std::size_t rounds = 100000; + + for (std::size_t i = 0; i < rounds; ++i) + { + { + exprtk::parser parser; + if (!parser.compile(expression_string,expression)) + { + std::cout << "run_test11() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl; + return false; + } + } + if (not_equal(expression.value(),(x + y)/T(3.0),0.000001)) + { + printf("run_test11() - Error in evaluation!(1)\n"); + return false; + } + expression.release(); + T result2 = expression.value(); + if (result2 == result2) + { + printf("run_test11() - Error in evaluation!(2)\n"); + return false; + } + { + exprtk::parser parser; + if (!parser.compile(expression_string,expression)) + { + std::cout << "run_test11() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl; + return false; + } + } + if (not_equal(expression.value(),(x + y)/T(3.0),0.000001)) + { + printf("run_test11() - Error in evaluation!(3)\n"); + return false; + } + } + return true; +} + int main() { return ( @@ -1841,7 +1908,8 @@ int main() run_test07() && run_test08() && run_test09() && - run_test10() + run_test10() && + run_test11() ) ? 0 : 1; } diff --git a/readme.txt b/readme.txt index 59b52e3..5c0c3db 100644 --- a/readme.txt +++ b/readme.txt @@ -20,7 +20,7 @@ http://www.opensource.org/licenses/cpl1.0.php All updates and the most recent version of the C++ Mathematical Expression Library can be found at: (1) http://www.partow.net/programming/exprtk/index.html - +(2) svn checkout http://exprtk.googlecode.com/svn/ exprtk [INSTALLATION] (1) exprtk.hpp should be placed in a project or system include path