From 64a4f623a3542a0eb9e969336e53216f36ee35c4 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Wed, 14 Mar 2012 07:12:58 +1100 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- Makefile | 10 +- exprtk.hpp | 3138 +++++++++++++++++++++++++++++++++++++++++------ exprtk_test.cpp | 238 +++- readme.txt | 1 + 4 files changed, 2951 insertions(+), 436 deletions(-) diff --git a/Makefile b/Makefile index 27c687a..4801654 100644 --- a/Makefile +++ b/Makefile @@ -23,15 +23,23 @@ OPTIONS = $(BASE_OPTIONS) $(OPTIMIZATION_OPT) -o LINKER_OPT = -L/usr/lib -lstdc++ BUILD_LIST+=exprtk_test +BUILD_LIST+=exprtk_benchmark all: $(BUILD_LIST) exprtk_test: exprtk_test.cpp exprtk.hpp $(COMPILER) $(OPTIONS) exprtk_test exprtk_test.cpp $(LINKER_OPT) +exprtk_benchmark: exprtk_benchmark.cpp exprtk.hpp + $(COMPILER) $(OPTIONS) exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT) -pgo: exprtk_test.cpp exprtk.hpp +pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_test exprtk_test.cpp $(LINKER_OPT) + $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT) + ./exprtk_test + ./exprtk_benchmark + $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-use -o exprtk_test exprtk_test.cpp $(LINKER_OPT) + $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-use -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT) strip_bin: strip -s exprtk_test diff --git a/exprtk.hpp b/exprtk.hpp index 30d8b7d..d0bd52c 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -1,30 +1,31 @@ /* - ************************************************************** - * C++ Mathematical Expression Toolkit Library * - * * - * Author: Arash Partow (1999-2012) * - * URL: http://www.partow.net/programming/exprtk/index.html * - * * - * Copyright notice: * - * Free use of the Mathematical Expression Toolkit Library is * - * permitted under the guidelines and in accordance with the * - * most current version of the Common Public License. * - * http://www.opensource.org/licenses/cpl1.0.php * - * * - * Example expressions: * - * (00) (y+x/y)*(x-y/x) * - * (01) (x^2/sin(2*pi/y))-x/2 * - * (02) sqrt(1-(x^2)) * - * (03) 1-sin(2*x)+cos(pi/y) * - * (04) a*exp(2*t)+c * - * (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) * - * (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x * - * (07) z:=x+sin(2*pi/y) * - * (08) u<-2*(pi*z)/(w:=x+cos(y/pi)) * - * (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) * - * (10) inrange(-2,m,+2)==if(({-2<=m}and[m<=+2]),1,0) * - * * - ************************************************************** + **************************************************************** + * C++ Mathematical Expression Toolkit Library * + * * + * Author: Arash Partow (1999-2012) * + * URL: http://www.partow.net/programming/exprtk/index.html * + * * + * Copyright notice: * + * Free use of the C++ Mathematical Expression Toolkit Library * + * is permitted under the guidelines and in accordance with the * + * most current version of the Common Public License. * + * http://www.opensource.org/licenses/cpl1.0.php * + * * + * Example expressions: * + * (00) (y+x/y)*(x-y/x) * + * (01) (x^2/sin(2*pi/y))-x/2 * + * (02) sqrt(1-(x^2)) * + * (03) 1-sin(2*x)+cos(pi/y) * + * (04) a*exp(2*t)+c * + * (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) * + * (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x * + * (07) z:=x+sin(2*pi/y) * + * (08) u<-2*(pi*z)/(w:=x+cos(y/pi)) * + * (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) * + * (10) inrange(-2,m,+2)==if(({-2<=m}and[m<=+2]),1,0) * + * (11) (12.34sin(x)cos(2y)7+1)==(12.34*sin(x)*cos(2*y)*7+1) * + * * + **************************************************************** */ @@ -38,9 +39,11 @@ #include #include #include +#include #include #include + namespace exprtk { namespace details @@ -50,13 +53,14 @@ namespace exprtk return (' ' == c) || ('\n' == c) || ('\r' == c) || - ('\t' == c); + ('\t' == c) || + ('\b' == c); } inline bool is_operator_char(const char& c) { - return ('*' == c) || ('/' == c) || - ('+' == c) || ('-' == c) || + return ('+' == c) || ('-' == c) || + ('*' == c) || ('/' == c) || ('^' == c) || ('<' == c) || ('>' == c) || ('=' == c) || (',' == c) || ('!' == c) || @@ -99,7 +103,13 @@ namespace exprtk !is_digit(c) && ('.' != c) && ('_' != c) && - ('$' != c); + ('$' != c) && + ('\'' != c); + } + + inline bool imatch(const char& c1, const char& c2) + { + return std::tolower(c1) == std::tolower(c2); } inline bool imatch(const std::string& s1, const std::string& s2) @@ -115,21 +125,50 @@ namespace exprtk } return true; } - else - return false; + return false; } + static const std::string reserved_words[] = + { + "and", "for", "if", "nand", "nor", "not", "or", "while", "xor" + }; + static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); + static const std::string reserved_symbols[] = { "abs", "acos", "and", "asin", "atan", "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", "csc", "deg2grad", "deg2rad", "equal", "exp", - "floor", "for", "grad2deg", "hyp", "inrange", "log", "log10", "logn", + "floor", "for", "grad2deg", "hyp", "if", "inrange", "log", "log10", "logn", "max", "min", "mod", "mul", "nand", "nor", "not", "not_equal", "or", "rad2deg", "root", "round", "roundn", "sec", "shl", "shr", "sin", "sinh", "sqrt", "sum", "tan", "tanh", "while", "xor" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); + inline bool is_reserved_word(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_words_size; ++i) + { + if (imatch(symbol,reserved_words[i])) + { + return true; + } + } + return false; + } + + inline bool is_reserved_symbol(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_symbols_size; ++i) + { + if (imatch(symbol,reserved_symbols[i])) + { + return true; + } + } + return false; + } + static const double pow10[] = { 1.0, 10.0, @@ -325,8 +364,28 @@ namespace exprtk return v0 << v1; } + template + inline T xor_impl(const T& v0, const T& v1, real_type_tag) + { + return v0 != v1; + } + + template + inline T xor_impl(const T& v0, const T& v1, int_type_tag) + { + return v0 ^ v1; + } + } + template + struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; + + template<> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; }; + template<> struct numeric_info { enum { min_exp = -38, max_exp = +38}; }; + template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + template inline T equal(const T& v0, const T& v1) { @@ -403,6 +462,14 @@ namespace exprtk typename details::number_type::type num_type; return details::shl_impl(v0,v1,num_type); } + + template + inline T xor_opr(const T& v0, const T& v1) + { + typename details::number_type::type num_type; + return details::xor_impl(v0,v1,num_type); + } + } template @@ -416,12 +483,13 @@ namespace exprtk eof = 2, number = 3, symbol = 4, - assign = 5, - shr = 6, - shl = 7, - lte = 8, - ne = 9, - gte = 10, + string = 5, + assign = 6, + shr = 7, + shl = 8, + lte = 9, + ne = 10, + gte = 11, lt = '<', gt = '>', eq = '=', @@ -442,12 +510,24 @@ namespace exprtk token() {} + explicit token(token_type ttype) + : type(ttype) + {} + token(token_type ttype, - const char* begin, const char* end, - const T& numeric_value = T(0)) + const char* begin, const char* end) : type(ttype), - value(std::string(begin,end)), - numeric_value(numeric_value) + value(std::string(begin,end)) + {} + + token(token_type ttype, const std::string& v) + : type(ttype), + value(v) + {} + + token(token_type ttype, const T& num_val) + : type(ttype), + numeric_value(num_val) {} token_type type; @@ -477,6 +557,7 @@ namespace exprtk return false; } } + process_commutative_symbols(); token_itr_ = token_list_.begin(); store_token_itr_ = token_list_.begin(); return true; @@ -509,12 +590,17 @@ namespace exprtk private: - inline void scan_token() + inline void skip_whitespace() { while ((s_end != s_itr) && is_whitespace(*s_itr)) { ++s_itr; } + } + + inline void scan_token() + { + skip_whitespace(); if (s_end == s_itr) { @@ -522,34 +608,7 @@ namespace exprtk } else if (is_operator_char(*s_itr)) { - if ((s_itr + 1) != s_end) - { - typename token_t::token_type ttype = token_t::none; - char c0 = s_itr[0]; - char c1 = s_itr[1]; - if ((c0 == '<') && (c1 == '=')) ttype = token_t::lte; - else if ((c0 == '>') && (c1 == '=')) ttype = token_t::gte; - else if ((c0 == '<') && (c1 == '>')) ttype = token_t::ne; - else if ((c0 == '!') && (c1 == '=')) ttype = token_t::ne; - else if ((c0 == '=') && (c1 == '=')) ttype = token_t::eq; - else if ((c0 == ':') && (c1 == '=')) ttype = token_t::assign; - else if ((c0 == '<') && (c1 == '-')) ttype = token_t::assign; - else if ((c0 == '<') && (c1 == '<')) ttype = token_t::shl; - else if ((c0 == '>') && (c1 == '>')) ttype = token_t::shr; - if (token_t::none != ttype) - { - token_list_.push_back(token_t(ttype,s_itr,s_itr + 2)); - s_itr += 2; - return; - } - } - if ('<' == *s_itr) - token_list_.push_back(token_t(token_t::lt,s_itr,s_itr + 1)); - else if ('>' == *s_itr) - token_list_.push_back(token_t(token_t::gt,s_itr,s_itr + 1)); - else - token_list_.push_back(token_t(typename token_t::token_type((*s_itr)),s_itr,s_itr + 1)); - ++s_itr; + scan_operator(); return; } else if (is_letter(*s_itr)) @@ -562,11 +621,16 @@ namespace exprtk scan_number(); return; } - if ('$' == (*s_itr)) + else if ('$' == (*s_itr)) { scan_special_function(); return; } + else if ('\'' == (*s_itr)) + { + scan_string(); + return; + } else { set_error(std::string("scan_token() - error invalid token: ") + std::string(s_itr,s_itr + 2)); @@ -575,6 +639,36 @@ namespace exprtk } } + inline void scan_operator() + { + if ((s_itr + 1) != s_end) + { + typename token_t::token_type ttype = token_t::none; + char c0 = s_itr[0]; + char c1 = s_itr[1]; + if ((c0 == '<') && (c1 == '=')) ttype = token_t::lte; + else if ((c0 == '>') && (c1 == '=')) ttype = token_t::gte; + else if ((c0 == '<') && (c1 == '>')) ttype = token_t::ne; + else if ((c0 == '!') && (c1 == '=')) ttype = token_t::ne; + else if ((c0 == '=') && (c1 == '=')) ttype = token_t::eq; + else if ((c0 == ':') && (c1 == '=')) ttype = token_t::assign; + else if ((c0 == '<') && (c1 == '-')) ttype = token_t::assign; + else if ((c0 == '<') && (c1 == '<')) ttype = token_t::shl; + else if ((c0 == '>') && (c1 == '>')) ttype = token_t::shr; + if (token_t::none != ttype) + { + token_list_.push_back(token_t(ttype)); + s_itr += 2; + return; + } + } + if ('<' == *s_itr) token_list_.push_back(token_t(token_t::lt)); + else if ('>' == *s_itr) token_list_.push_back(token_t(token_t::gt)); + else + token_list_.push_back(token_t(typename token_t::token_type((*s_itr)))); + ++s_itr; + } + inline void scan_symbol() { const char* begin = s_itr; @@ -617,7 +711,7 @@ namespace exprtk ++s_itr; continue; } - else if (('e' == (*s_itr)) || ('E' == (*s_itr))) + else if (imatch('e',(*s_itr))) { const char& c = *(s_itr + 1); if (s_end == (s_itr + 1)) @@ -653,8 +747,14 @@ namespace exprtk else ++s_itr; } - T nval = T(atof(std::string(begin,s_itr).c_str())); - token_list_.push_back(token_t(token_t::number,begin,s_itr,nval)); + T value = T(0.0); + if (string_to_real(begin,s_itr,value)) + token_list_.push_back(token_t(token_t::number,value)); + else + { + set_error(std::string("scan_number() - error failed to parse token to real type. ") + std::string(begin,s_itr)); + token_list_.push_back(error(begin,s_itr)); + } return; } @@ -669,10 +769,10 @@ namespace exprtk return; } - if (!(('$' == *s_itr) && - ('f' == *(s_itr + 1)) && - ('(' == *(s_itr + 4)) && - (is_digit(*(s_itr + 2))) && + if (!(('$' == *s_itr) && + (imatch('f',*(s_itr + 1))) && + ('(' == *(s_itr + 4)) && + (is_digit(*(s_itr + 2))) && (is_digit(*(s_itr + 3))))) { set_error(std::string("scan_special_function() - error invalid special function [2]: ") + std::string(begin,s_itr)); @@ -684,6 +784,78 @@ namespace exprtk return; } + inline void scan_string() + { + const char* begin = s_itr + 1; + if (std::distance(s_itr,s_end) < 2) + { + set_error(std::string("scan_string() - error invalid string [1]: ") + std::string(begin,s_itr)); + token_list_.push_back(error(begin,s_itr)); + return; + } + ++s_itr; + bool escaped = false; + std::string result_string; + while (s_end != s_itr) + { + if ('\\' == *s_itr) + { + escaped = true; + ++s_itr; + continue; + } + else if (!escaped) + { + if ('\'' == *s_itr) + break; + } + else if (escaped) + escaped = false; + result_string += *s_itr; + ++s_itr; + } + if (s_end == s_itr) + { + set_error(std::string("scan_string() - error string has not been terminated: ") + std::string(begin,s_itr)); + token_list_.push_back(error(begin,s_itr)); + return; + } + token_list_.push_back(token_t(token_t::string,result_string)); + ++s_itr; + return; + } + + inline void process_commutative_symbols() + { + if (token_list_.size() < 2) + return; + typename std::deque::iterator itr = token_list_.begin() + 1; + typename std::deque::iterator prev_itr = token_list_.begin(); + while (token_list_.end() != itr) + { + token_t& curr_token = *itr; + token_t& prev_token = *prev_itr; + bool curr_token_not_reserved = !is_reserved_word(curr_token.value); + if ( + //3x -> 3*x + ((token_t::symbol == curr_token.type) && (token_t::number == prev_token.type) && curr_token_not_reserved) || + //3(x+1) -> 3*(x+1) + (is_left_bracket(curr_token.type) && (token_t::number == prev_token.type)) || + //(x+1)3 -> (x+1)*3 + (is_right_bracket(prev_token.type) && (token_t::number == curr_token.type)) || + //(x+1)y -> (x+1)*y + (is_right_bracket(prev_token.type) && (token_t::symbol == curr_token.type) && curr_token_not_reserved) + ) + { + prev_itr = itr = token_list_.insert(itr,token_t(token_t::mul)); + ++itr; + continue; + } + ++itr; + ++prev_itr; + } + } + inline void set_error(const std::string& s) { if (error_description_.empty()) @@ -692,13 +864,337 @@ namespace exprtk } } - inline token_t error(const char* begin, const char* end) + inline token_t error(const char* begin, const char* end) const { return token_t(token_t::error,begin,end); } private: + template + static inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, Type& result) + { + if (end == itr) return false; + + Type t = 0; + bool negative = false; + + if ('+' == (*itr)) + ++itr; + else if ('-' == (*itr)) + { + ++itr; + negative = true; + } + + if (end == itr) + return false; + + unsigned int digit_count = 0; + while ((end != itr) && ('0' == (*itr))) ++itr; + + bool return_result = true; + while (end != itr) + { + const unsigned char digit = (*itr - '0'); + if (digit > 9) + { + return_result = false; + break; + } + + if ((++digit_count) <= numeric::numeric_info::bound_length) + { + t *= 10; + t += digit; + } + else + { + typedef unsigned long long int base_type; + static const base_type max_limit = +std::numeric_limits::max(); + static const base_type min_limit = -std::numeric_limits::min(); + base_type tmp = static_cast(t) * 10 + digit; + if (negative && static_cast(tmp) > min_limit) + return_result = false; + else if (static_cast(tmp) > max_limit) + return_result = false; + t = static_cast(tmp); + } + ++itr; + } + + result = static_cast((negative) ? -t : t); + return return_result; + } + + template + static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) + { + typedef typename std::iterator_traits::value_type type; + static const std::size_t nan_length = 3; + if (std::distance(itr,end) != static_cast(nan_length)) + return false; + if (static_cast('n') == (*itr)) + { + if ((static_cast('a') != *(itr + 1)) || (static_cast('n') != *(itr + 2))) + { + return false; + } + } + else if ((static_cast('A') != *(itr + 1)) || (static_cast('N') != *(itr + 2))) + { + return false; + } + t = std::numeric_limits::quiet_NaN(); + return true; + } + + template + static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) + { + static const char inf_uc[] = "INFINITY"; + static const char inf_lc[] = "infinity"; + static const std::size_t inf_length = 8; + const std::size_t length = std::distance(itr,end); + if ((3 != length) && (inf_length != length)) + return false; + const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + while (end != itr) + { + if (*inf_itr == static_cast(*itr)) + { + ++itr; + ++inf_itr; + continue; + } + else + return false; + } + if (negative) + t = -std::numeric_limits::infinity(); + else + t = std::numeric_limits::infinity(); + return true; + } + + template + inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t) + { + if (end == itr_external) return false; + Iterator itr = itr_external; + double d = 0.0; + bool negative = false; + if ('+' == (*itr)) + ++itr; + else if ('-' == (*itr)) + { + ++itr; + negative = true; + } + + if (end == itr) + return false; + + if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr,end,t,negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr,end,t); + } + else + return false; + } + + bool instate = false; + int pre_decimal = 0; + + if ('.' != (*itr)) + { + const Iterator curr = itr; + while ((end != itr) && ('0' == (*itr))) ++itr; + const Iterator post_zero_cull_itr = itr; + unsigned char digit = 0; + + #define parse_digit_1 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= 10.0; d += digit; } else break; if (end == ++itr) break; \ + + #define parse_digit_2 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= 10.0; d += digit; } else break; ++itr;\ + + while (end != itr) + { + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_2 + } + #undef parse_digit_1 + #undef parse_digit_2 + if (curr != itr) instate = true; + pre_decimal = static_cast(std::distance(post_zero_cull_itr,itr)); + } + + int exponent = 0; + + if (end != itr) + { + if ('.' == (*itr)) + { + ++itr; + const Iterator curr = itr; + unsigned char digit = 0; + + #define parse_digit_1 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= 10.0; d += digit; } else break; if (end == ++itr) break; \ + + #define parse_digit_2 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= 10.0; d += digit; } else break; ++itr;\ + + while (end != itr) + { + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_2 + } + #undef parse_digit_1 + #undef parse_digit_2 + if (curr != itr) instate = true; + exponent -= static_cast(std::distance(curr,itr)); + } + + if (end != itr) + { + typename std::iterator_traits::value_type c = (*itr); + + if (('e' == c) || ('E' == c)) + { + ++itr; + int exp = 0; + if (!string_to_type_converter_impl_ref(itr,end,exp)) + { + if (end == itr) + return false; + else + c = (*itr); + } + + if ( + (exp < numeric::numeric_info::min_exp) || + (numeric::numeric_info::max_exp < exp) + ) + return false; + + exponent += exp; + } + + if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) + ++itr; + else if ('#' == c) + { + ++itr; + if (end == itr) + return false; + if ((10.0 != d) || (exponent != -1)) + return false; + if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr,end,t,negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr,end,t); + } + else + return false; + } + return false; + } + } + } + + if ((end != itr) || (!instate)) + return false; + + if (0 != exponent) + { + if ( + (std::numeric_limits::max_exponent10 < (exponent + pre_decimal)) || + (std::numeric_limits::min_exponent10 > (exponent + pre_decimal)) + ) + { + return false; + } + + const int e = std::abs(exponent); + static const double fract10[] = + { + 0.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, + 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, + 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, + 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, + 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, + 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, + 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, + 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, + 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, + 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, + 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, + 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, + 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, + 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, + 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, + 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, + 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, + 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, + 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, + 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, + 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, + 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, + 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, + 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, + 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, + 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, + 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, + 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 + }; + + static const std::size_t fract10_size = sizeof(fract10) / sizeof(double); + + if (d != 0.0) + { + if (static_cast(e) < fract10_size) + { + if (exponent > 0) + d *= fract10[e]; + else + d /= fract10[e]; + } + else + d *= std::pow(10.0, 1.0 * exponent); + } + } + + t = static_cast((negative) ? -d : d); + return true; + } + std::string error_description_; std::deque token_list_; typename std::deque::iterator token_itr_; @@ -855,7 +1351,7 @@ namespace exprtk case e_d2g : return (arg * T(20/9)); case e_g2d : return (arg * T(9/20)); case e_not : return (arg != T(0) ? T(0) : T(1)); - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -872,7 +1368,7 @@ namespace exprtk case e_pos : return +arg; case e_sqrt : return std::sqrt (arg); case e_not : return !arg; - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -912,7 +1408,7 @@ namespace exprtk case e_prod : return (arg0 * arg1); case e_shr : return shr(arg0,arg1); case e_shl : return shl(arg0,arg1); - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -940,7 +1436,7 @@ namespace exprtk case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); - case e_xor : return (arg0 != arg1) ? T(1) : T(0); + case e_xor : return arg0 ^ arg1; case e_root : return root(arg0,arg1); case e_equal : return arg0 == arg1; case e_nequal : return arg0 != arg1; @@ -950,7 +1446,7 @@ namespace exprtk case e_prod : return (arg0 * arg1); case e_shr : return arg0 >> arg1; case e_shl : return arg0 << arg1; - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } } @@ -988,7 +1484,27 @@ namespace exprtk e_conditional , e_while , e_variable , - e_function + e_stringvar , + e_stringconst , + e_function , + e_add , + e_sub , + e_mul , + e_div , + e_mod , + e_pow , + e_lt , + e_lte , + e_gt , + e_gte , + e_eq , + e_ne , + e_and , + e_nand , + e_or , + e_nor , + e_xor , + e_vov }; typedef T value_type; @@ -997,11 +1513,16 @@ namespace exprtk virtual ~expression_node() {} - virtual inline T value() + virtual inline T value() const { return std::numeric_limits::quiet_NaN(); } + virtual inline expression_node* branch(const std::size_t& index = 0) const + { + return reinterpret_cast(index * 0); + } + virtual inline node_type type() const { return e_none; @@ -1009,9 +1530,39 @@ namespace exprtk }; template - inline bool branch_deletable(expression_node* expr) + inline bool is_unary_node(const expression_node* node) { - return expression_node::e_variable != expr->type(); + return (details::expression_node::e_unary == node->type()); + } + + template + inline bool is_binary_node(const expression_node* node) + { + return (details::expression_node::e_binary == node->type()); + } + + template + inline bool is_variable_node(const expression_node* node) + { + return (details::expression_node::e_variable == node->type()); + } + + template + inline bool is_constant_node(const expression_node* node) + { + return (details::expression_node::e_constant == node->type()); + } + + template + inline bool is_function(const expression_node* node) + { + return (details::expression_node::e_function == node->type()); + } + + template + inline bool branch_deletable(expression_node* node) + { + return !is_variable_node(node); } template @@ -1023,7 +1574,7 @@ namespace exprtk : value_(value) {} - inline T value() + inline T value() const { return value_; } @@ -1033,11 +1584,52 @@ namespace exprtk return expression_node::e_constant; } + inline expression_node* branch(const std::size_t& index = 0) const + { + return reinterpret_cast*>(index * 0); + } + private: T value_; }; + + template + class string_literal_node : public expression_node + { + public: + + explicit string_literal_node(const std::string& value) + : value_(value) + {} + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringconst; + } + + inline expression_node* branch(const std::size_t& index = 0) const + { + return reinterpret_cast*>(index * 0); + } + + inline std::string str() + { + return value_; + } + + private: + + const std::string value_; + }; + + template class unary_node : public expression_node { @@ -1052,12 +1644,16 @@ namespace exprtk branch_deletable_(branch_deletable(branch_)) {} - ~unary_node() + ~unary_node() { - if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } + if (branch_ && branch_deletable_) + { + delete branch_; + branch_ = 0; + } } - inline T value() + inline T value() const { const T arg = branch_->value(); return numeric::process(operation_,arg); @@ -1068,6 +1664,19 @@ namespace exprtk return expression_node::e_unary; } + inline operator_type operation() const + { + return operation_; + } + + inline expression_node* branch(const std::size_t& index = 0) const + { + if (0 == index) + return branch_; + else + return reinterpret_cast(0); + } + private: operator_type operation_; @@ -1143,7 +1752,7 @@ namespace exprtk cleanup_branches<2>(branch_); } - inline T value() + inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -1155,6 +1764,21 @@ namespace exprtk return expression_node::e_binary; } + inline operator_type operation() const + { + return operation_; + } + + inline expression_node* branch(const std::size_t& index = 0) const + { + if (0 == index) + return branch_[0].first; + else if (1 == index) + return branch_[1].first; + else + return reinterpret_cast(0); + } + protected: operator_type operation_; @@ -1183,7 +1807,7 @@ namespace exprtk cleanup_branches<3>(branch_); } - inline T value() + inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -1197,7 +1821,7 @@ namespace exprtk case e_avg : return (arg0 + arg1 + arg2) / T(3.0); case e_sum : return (arg0 + arg1 + arg2); case e_prod : return (arg0 * arg1 * arg2); - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -1235,7 +1859,7 @@ namespace exprtk cleanup_branches<4>(branch_); } - inline T value() + inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -1248,7 +1872,7 @@ namespace exprtk case e_avg : return (arg0 + arg1 + arg2 + arg3) / T(4.0); case e_sum : return (arg0 + arg1 + arg2 + arg3); case e_prod : return (arg0 * arg1 * arg2 * arg3); - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -1287,7 +1911,7 @@ namespace exprtk cleanup_branches<5>(branch_); } - inline T value() + inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -1301,7 +1925,7 @@ namespace exprtk case e_avg : return (arg0 + arg1 + arg2 + arg3 + arg4) / T(5.0); case e_sum : return (arg0 + arg1 + arg2 + arg3 + arg4); case e_prod : return (arg0 * arg1 * arg2 * arg3 * arg4); - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -1341,7 +1965,7 @@ namespace exprtk cleanup_branches<6>(branch_); } - inline T value() + inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -1357,7 +1981,7 @@ namespace exprtk case e_sum : return (arg0 + arg1 + arg2 + arg3 + arg4 + arg5); case e_prod : return (arg0 * arg1 * arg2 * arg3 * arg4 * arg5); case e_default : - default : return std::numeric_limits::infinity(); + default : return std::numeric_limits::quiet_NaN(); } } @@ -1385,9 +2009,9 @@ namespace exprtk : test_(test), consequent_(consequent), alternative_(alternative), - test_deletable_(expression_node::e_variable != test_->type()), - consequent_deletable_(expression_node::e_variable != consequent_->type()), - alternative_deletable_(expression_node::e_variable != alternative_->type()) + test_deletable_(!is_variable_node(test_)), + consequent_deletable_(!is_variable_node(consequent_)), + alternative_deletable_(!is_variable_node(alternative_)) {} ~conditional_node() @@ -1397,7 +2021,7 @@ namespace exprtk if (alternative_ && alternative_deletable_) delete alternative_; } - inline T value() + inline T value() const { if (test_->value() != 0) return consequent_->value(); @@ -1431,17 +2055,17 @@ namespace exprtk expression_ptr branch) : test_(test), branch_(branch), - test_deletable_(expression_node::e_variable != test_->type()), - branch_deletable_(expression_node::e_variable != branch_->type()) + test_deletable_(!is_variable_node(test_)), + branch_deletable_(!is_variable_node(branch_)) {} ~while_loop_node() { - if (test_ && test_deletable_) delete test_; + if (test_ && test_deletable_) delete test_; if (branch_ && branch_deletable_) delete branch_; } - inline T value() + inline T value() const { T result = T(0); while (test_->value() != T(0)) @@ -1484,7 +2108,7 @@ namespace exprtk return this < (&v); } - inline T value() + inline T value() const { return (*value_); } @@ -1510,9 +2134,108 @@ namespace exprtk }; template - T variable_node::null_value = T(std::numeric_limits::infinity()); + T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + template + class stringvar_node : public expression_node + { + public: + + static std::string null_value; + + explicit stringvar_node() + : value_(&null_value) + {} + + explicit stringvar_node(T& value) + : value_(&value) + {} + + inline bool operator <(const stringvar_node& v) const + { + return this < (&v); + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline std::string str() const + { + return (*value_); + } + + inline std::string& ref() + { + return (*value_); + } + + inline const std::string& ref() const + { + return (*value_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvar; + } + + private: + + std::string* value_; + + }; + + template + std::string stringvar_node::null_value = std::string(""); + + template struct sf00_op { static inline T process(const T& x, const T& y, const T& z) { return (x + y) / z; } }; + template struct sf01_op { static inline T process(const T& x, const T& y, const T& z) { return (x + y) * z; } }; + template struct sf02_op { static inline T process(const T& x, const T& y, const T& z) { return (x - y) / z; } }; + template struct sf03_op { static inline T process(const T& x, const T& y, const T& z) { return (x - y) * z; } }; + template struct sf04_op { static inline T process(const T& x, const T& y, const T& z) { return (x * y) + z; } }; + template struct sf05_op { static inline T process(const T& x, const T& y, const T& z) { return (x * y) - z; } }; + template struct sf06_op { static inline T process(const T& x, const T& y, const T& z) { return (x * y) / z; } }; + template struct sf07_op { static inline T process(const T& x, const T& y, const T& z) { return (x * y) * z; } }; + template struct sf08_op { static inline T process(const T& x, const T& y, const T& z) { return (x / y) + z; } }; + template struct sf09_op { static inline T process(const T& x, const T& y, const T& z) { return (x / y) - z; } }; + template struct sf10_op { static inline T process(const T& x, const T& y, const T& z) { return (x / y) / z; } }; + template struct sf11_op { static inline T process(const T& x, const T& y, const T& z) { return (x / y) * z; } }; + template struct sf12_op { static inline T process(const T& x, const T& y, const T& z) { return z / (x + y); } }; + template struct sf13_op { static inline T process(const T& x, const T& y, const T& z) { return z / (x - y); } }; + template struct sf14_op { static inline T process(const T& x, const T& y, const T& z) { return z / (x * y); } }; + template struct sf15_op { static inline T process(const T& x, const T& y, const T& z) { return z / (x / y); } }; + template struct sf16_op { static inline T process(const T& x, const T& y, const T& z) { return z - (x / y); } }; + template struct sf17_op { static inline T process(const T& x, const T& y, const T& z) { return z - (x / y); } }; + template struct sf18_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x + y) / z); } }; + template struct sf19_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x + y) * z); } }; + template struct sf20_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x - y) / z); } }; + template struct sf21_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x - y) * z); } }; + template struct sf22_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x * y) / z); } }; + template struct sf23_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x * y) * z); } }; + template struct sf24_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x / y) + z); } }; + template struct sf25_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x / y) / z); } }; + template struct sf26_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w + ((x / y) * z); } }; + template struct sf27_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x + y) / z); } }; + template struct sf28_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x + y) * z); } }; + template struct sf29_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x - y) / z); } }; + template struct sf30_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x - y) * z); } }; + template struct sf31_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x * y) / z); } }; + template struct sf32_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x * y) * z); } }; + template struct sf33_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x / y) / z); } }; + template struct sf34_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return w - ((x / y) * z); } }; + template struct sf35_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x + y) * z) - w; } }; + template struct sf36_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x - y) * z) - w; } }; + template struct sf37_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x * y) * z) - w; } }; + template struct sf38_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x / y) * z) - w; } }; + template struct sf39_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x + y) / z) - w; } }; + template struct sf40_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x - y) / z) - w; } }; + template struct sf41_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x * y) / z) - w; } }; + template struct sf42_op { static inline T process(const T& x, const T& y, const T& z, const T& w) { return ((x / y) / z) - w; } }; + + template class sf3_node : public trinary_node { public: @@ -1526,37 +2249,16 @@ namespace exprtk : trinary_node(operation,branch0,branch1,branch2) {} - inline T value() + inline T value() const { const T x = trinary_node::branch_[0].first->value(); const T y = trinary_node::branch_[1].first->value(); const T z = trinary_node::branch_[2].first->value(); - switch (trinary_node::operation_) - { - case e_sf00 : return (x + y) / z; - case e_sf01 : return (x + y) * z; - case e_sf02 : return (x - y) / z; - case e_sf03 : return (x - y) * z; - case e_sf04 : return (x * y) + z; - case e_sf05 : return (x * y) - z; - case e_sf06 : return (x * y) / z; - case e_sf07 : return (x * y) * z; - case e_sf08 : return (x / y) + z; - case e_sf09 : return (x / y) - z; - case e_sf10 : return (x / y) / z; - case e_sf11 : return (x / y) * z; - case e_sf12 : return z / (x + y); - case e_sf13 : return z / (x - y); - case e_sf14 : return z / (x * y); - case e_sf15 : return z / (x / y); - case e_sf16 : return z - (x / y); - case e_sf17 : return z - (x / y); - default : return std::numeric_limits::infinity(); - } + return SpecialFunction::process(x,y,z); } }; - template + template class sf4_node : public quaternary_node { public: @@ -1571,41 +2273,13 @@ namespace exprtk : quaternary_node(operation,branch0,branch1,branch2,branch3) {} - inline T value() + inline T value() const { const T x = quaternary_node::branch_[0].first->value(); const T y = quaternary_node::branch_[1].first->value(); const T z = quaternary_node::branch_[2].first->value(); const T w = quaternary_node::branch_[3].first->value(); - switch (quaternary_node::operation_) - { - case e_sf18 : return w + ((x + y) / z); - case e_sf19 : return w + ((x + y) * z); - case e_sf20 : return w + ((x - y) / z); - case e_sf21 : return w + ((x - y) * z); - case e_sf22 : return w + ((x * y) / z); - case e_sf23 : return w + ((x * y) * z); - case e_sf24 : return w + ((x / y) + z); - case e_sf25 : return w + ((x / y) / z); - case e_sf26 : return w + ((x / y) * z); - case e_sf27 : return w - ((x + y) / z); - case e_sf28 : return w - ((x + y) * z); - case e_sf29 : return w - ((x - y) / z); - case e_sf30 : return w - ((x - y) * z); - case e_sf31 : return w - ((x * y) / z); - case e_sf32 : return w - ((x * y) * z); - case e_sf33 : return w - ((x / y) / z); - case e_sf34 : return w - ((x / y) * z); - case e_sf35 : return ((x + y) * z) - w; - case e_sf36 : return ((x - y) * z) - w; - case e_sf37 : return ((x * y) * z) - w; - case e_sf38 : return ((x / y) * z) - w; - case e_sf39 : return ((x + y) / z) - w; - case e_sf40 : return ((x - y) / z) - w; - case e_sf41 : return ((x * y) / z) - w; - case e_sf42 : return ((x / y) / z) - w; - default : return std::numeric_limits::infinity(); - } + return SpecialFunction::process(x,y,z,w); } }; @@ -1622,17 +2296,19 @@ namespace exprtk : binary_node(operation,branch0,branch1) {} - inline T value() + inline T value() const { - variable_node* var_node_ptr = dynamic_cast*>(binary_node::branch_[0].first); - if (var_node_ptr) + if (is_variable_node(binary_node::branch_[0].first)) { - T& result = dynamic_cast*>(binary_node::branch_[0].first)->ref(); - result = binary_node::branch_[1].first->value(); - return result; + variable_node* var_node_ptr = dynamic_cast*>(binary_node::branch_[0].first); + if (var_node_ptr) + { + T& result = var_node_ptr->ref(); + result = binary_node::branch_[1].first->value(); + return result; + } } - else - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } }; @@ -1657,15 +2333,16 @@ namespace exprtk } template - void init_branches(expression_ptr (&b)[NumBranches]) + bool init_branches(expression_ptr (&b)[NumBranches]) { for (std::size_t i = 0; i < NumBranches; ++i) { if (b[i]) - { branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); - } + else + return false; } + return true; } inline bool operator <(const function_node& fn) const @@ -1673,34 +2350,32 @@ namespace exprtk return this < (&fn); } - inline T value() + inline T value() const { T v[N]; if (function->param_count) { for (std::size_t i = 0; i < function->param_count; ++i) { - if (v[i]) - v[i] = branch_[i].first->value(); - else - std::numeric_limits::infinity(); + v[i] = branch_[i].first->value(); + } + switch (function->param_count) + { + case 1 : return (*function)(v[0]); + case 2 : return (*function)(v[0],v[1]); + case 3 : return (*function)(v[0],v[1],v[2]); + case 4 : return (*function)(v[0],v[1],v[2],v[3]); + case 5 : return (*function)(v[0],v[1],v[2],v[3],v[4]); + case 6 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5]); + case 7 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6]); + case 8 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]); + case 9 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); + case 10 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]); + default : return std::numeric_limits::quiet_NaN(); } } - switch (function->param_count) - { - case 0 : return (*function)(); - case 1 : return (*function)(v[0]); - case 2 : return (*function)(v[0],v[1]); - case 3 : return (*function)(v[0],v[1],v[2]); - case 4 : return (*function)(v[0],v[1],v[2],v[3]); - case 5 : return (*function)(v[0],v[1],v[2],v[3],v[4]); - case 6 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5]); - case 7 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6]); - case 8 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]); - case 9 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); - case 10 : return (*function)(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]); - default : return std::numeric_limits::infinity(); - } + else + return (*function)(); } inline typename expression_node::node_type type() const @@ -1714,6 +2389,627 @@ namespace exprtk branch_t branch_[N]; }; + template + struct add_op + { + static inline T process(const T& t1, const T& t2) { return t1 + t2; } + static inline typename expression_node::node_type type() { return expression_node::e_add; } + static inline details::operator_type operation() { return details::e_add; } + }; + + template + struct mul_op + { + static inline T process(const T& t1, const T& t2) { return t1 * t2; } + static inline typename expression_node::node_type type() { return expression_node::e_mul; } + static inline details::operator_type operation() { return details::e_mul; } + }; + + template + struct sub_op + { + static inline T process(const T& t1, const T& t2) { return t1 - t2; } + static inline typename expression_node::node_type type() { return expression_node::e_sub; } + static inline details::operator_type operation() { return details::e_sub; } + }; + + template + struct div_op + { + static inline T process(const T& t1, const T& t2) { return t1 / t2; } + static inline typename expression_node::node_type type() { return expression_node::e_div; } + static inline details::operator_type operation() { return details::e_div; } + }; + + template + struct mod_op + { + static inline T process(const T& t1, const T& t2) { return numeric::modulus(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_mod; } + static inline details::operator_type operation() { return details::e_mod; } + }; + + template + struct pow_op + { + static inline T process(const T& t1, const T& t2) { return numeric::pow(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_pow; } + static inline details::operator_type operation() { return details::e_pow; } + }; + + template + struct lt_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lt; } + static inline details::operator_type operation() { return details::e_lt; } + }; + + template + struct lte_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lte; } + static inline details::operator_type operation() { return details::e_lte; } + }; + + template + struct gt_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gt; } + static inline details::operator_type operation() { return details::e_gt; } + }; + + template + struct gte_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gte; } + static inline details::operator_type operation() { return details::e_gte; } + }; + + template + struct eq_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_eq; } + }; + + template + struct ne_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 != t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ne; } + static inline details::operator_type operation() { return details::e_ne; } + }; + + template + struct and_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 != T(0)) && (t2 != T(0))) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_and; } + static inline details::operator_type operation() { return details::e_and; } + }; + + template + struct nand_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 != T(0)) && (t2 != T(0))) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nand; } + static inline details::operator_type operation() { return details::e_nand; } + }; + + template + struct or_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 != T(0)) || (t2 != T(0))) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_or; } + static inline details::operator_type operation() { return details::e_or; } + }; + + template + struct nor_op + { + static inline T process(const T& t1, const T& t2) { return ((t1 != T(0)) || (t2 != T(0))) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_nor; } + }; + + template + struct xor_op + { + static inline T process(const T& t1, const T& t2) { return numeric::xor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xor; } + }; + + template + class vov_base_node : public expression_node + { + public: + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class cov_base_node : public expression_node + { + public: + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class sos_base_node : public expression_node + { + public: + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class vov_node : public vov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //variable op variable node + explicit vov_node(T& v0, T& v1) + : v0_(v0), + v1_(v1) + {} + + inline T value() const + { + return Operation::process(v0_,v1_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline T& v0() + { + return v0_; + } + + inline T& v1() + { + return v1_; + } + + protected: + + T& v0_; + T& v1_; + }; + + template + class vov_nodex : public vov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //variable op variable node + explicit vov_nodex(Type0 v0, Type1 v1) + : v0_(v0), + v1_(v1) + {} + + inline T value() const + { + return Operation::process(v0_,v1_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline Type0 v0() + { + return v0_; + } + + inline Type1 v1() + { + return v1_; + } + + protected: + + Type0 v0_; + Type1 v1_; + }; + + template + class cov_node : public cov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //constant op variable node + explicit cov_node(const T& c, T& v) + : c_(c), + v_(v) + {} + + inline T value() const + { + return Operation::process(c_,v_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline T c() + { + return c_; + } + + inline T& v() + { + return v_; + } + + protected: + + T c_; + T& v_; + }; + + template + class voc_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //variable op constant node + explicit voc_node(T& v, const T& c) + : v_(v), + c_(c) + {} + + inline T value() const + { + return Operation::process(v_,c_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + protected: + + T& v_; + T c_; + }; + + template + class vovov1_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + //variable0 op1 (variable1 op2 variable2) node + explicit vovov1_node(T& v0, vov_node& vn) + : v0_(v0), + v1_(vn.v0()), + v2_(vn.v1()) + {} + + inline T value() const + { + return Operation1::process(v0_,Operation2::process(v1_,v2_)); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_none; + } + + inline typename expression_node::node_type type1() const + { + return Operation1::type(); + } + + inline typename expression_node::node_type type2() const + { + return Operation2::type(); + } + + protected: + + T& v0_; + T& v1_; + T& v2_; + }; + + template + class vovov2_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + //(variable0 op1 variable1) op2 variable2 node + explicit vovov2_node(vov_node& vn, T& v2) + : v0_(vn.v0()), + v1_(vn.v1()), + v2_(v2) + {} + + inline T value() const + { + return Operation2::process(Operation1::process(v0_,v1_),v2_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_none; + } + + inline typename expression_node::node_type type1() const + { + return Operation1::type(); + } + + inline typename expression_node::node_type type2() const + { + return Operation2::type(); + } + + protected: + + T& v0_; + T& v1_; + T& v2_; + }; + + template + class covov1_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + //constant op1 (variable0 op2 variable1) node + explicit covov1_node(const T& c, vov_node& vn) + : c_(c), + v0_(vn.v0()), + v1_(vn.v1()) + {} + + inline T value() const + { + return Operation1::process(c_,Operation2::process(v0_,v1_)); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_none; + } + + inline typename expression_node::node_type type1() const + { + return Operation1::type(); + } + + inline typename expression_node::node_type type2() const + { + return Operation2::type(); + } + + protected: + + T c_; + T& v0_; + T& v1_; + }; + + template + class covov2_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + //(constant op1 variable0) op2 variable1 node + explicit covov2_node(cov_node& cvn, T& v1) + : c_ (cvn.c()), + v0_(cvn.v()), + v1_(v1) + {} + + inline T value() const + { + return Operation2::process(Operation1::process(c_,v0_),v1_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_none; + } + + inline typename expression_node::node_type type1() const + { + return Operation1::type(); + } + + inline typename expression_node::node_type type2() const + { + return Operation2::type(); + } + + protected: + + T c_; + T& v0_; + T& v1_; + }; + + template + class vovovov_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + //(variable0 op1 variable1) op2 (variable2 op3 variable3) node + explicit vovovov_node(vov_node& vn0, vov_node& vn1) + : v0_(vn0.v0()), + v1_(vn0.v1()), + v2_(vn1.v0()), + v3_(vn1.v1()) + {} + + inline T value() const + { + return Operation2::process(Operation1::process(v0_,v1_),Operation3::process(v2_,v3_)); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_none; + } + + inline typename expression_node::node_type type1() const + { + return Operation1::type(); + } + + inline typename expression_node::node_type type2() const + { + return Operation2::type(); + } + + protected: + + T& v0_; + T& v1_; + T& v2_; + T& v3_; + }; + + template + class sos_node : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + //variable op variable node + explicit sos_node(SType0 s0, SType1 s1) + : s0_(s0), + s1_(s1) + {} + + inline T value() const + { + return Operation::process(s0_,s1_); + } + + 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_; + } + + protected: + + SType0 s0_; + SType1 s1_; + }; + + template + inline bool is_vov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_string_node(const expression_node* node) + { + return (expression_node::e_stringvar == node->type()); + } + + template + inline bool is_const_string_node(const expression_node* node) + { + return (expression_node::e_stringconst == node->type()); + } + class node_allocator { public: @@ -1767,6 +3063,41 @@ namespace exprtk return new node_type(t1,t2); } + template + inline expression_node* allocate_cr(const T1& t1, T2& t2) const + { + return new node_type(t1,t2); + } + + template + inline expression_node* allocate_rc(T1& t1, const T2& t2) const + { + return new node_type(t1,t2); + } + + template + inline expression_node* allocate_rr(T1& t1, T2& t2) const + { + return new node_type(t1,t2); + } + + template + inline expression_node* allocate_tt(T1 t1, T2 t2) const + { + return new node_type(t1,t2); + } + + template + inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const + { + return new node_type(t1,t2,t3); + } + template @@ -1966,57 +3297,57 @@ namespace exprtk inline virtual T operator()() { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&,const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { - return std::numeric_limits::infinity(); + return std::numeric_limits::quiet_NaN(); } }; @@ -2048,6 +3379,13 @@ namespace exprtk typedef typename variable_map_t::iterator vm_itr_t; typedef typename variable_map_t::const_iterator vm_const_itr_t; + typedef typename details::stringvar_node stringvar_t; + typedef stringvar_t* stringvar_ptr; + typedef std::pair stringvar_pair_t; + typedef std::map stringvar_map_t; + typedef typename stringvar_map_t::iterator svm_itr_t; + typedef typename stringvar_map_t::const_iterator svm_const_itr_t; + typedef ifunction function_t; typedef function_t* function_ptr; typedef std::map function_map_t; @@ -2122,6 +3460,28 @@ namespace exprtk } } + inline stringvar_ptr get_stringvar(const std::string& string_name) + { + if (!valid_symbol(string_name)) + return reinterpret_cast(0); + else if (1 == string_name.size()) + { + stringvar_pair_t& svp = short_stringvar_lut_[static_cast(string_name[0])]; + if (svp.second) + return svp.second; + else + return reinterpret_cast(0); + } + else + { + svm_const_itr_t itr = stringvar_map_.find(string_name); + if (stringvar_map_.end() == itr) + return reinterpret_cast(0); + else + return itr->second.second; + } + } + inline function_ptr get_function(const std::string& function_name) { if (!valid_symbol(function_name)) @@ -2163,7 +3523,7 @@ namespace exprtk } } - inline bool is_constant(const std::string& symbol_name) const + inline bool is_constant_node(const std::string& symbol_name) const { if (1 == symbol_name.size()) { @@ -2179,11 +3539,38 @@ namespace exprtk } } + inline bool is_constant_string(const std::string& symbol_name) const + { + if (1 == symbol_name.size()) + { + return short_stringvar_lut_[static_cast(symbol_name[0])].first; + } + else + { + svm_const_itr_t itr = stringvar_map_.find(symbol_name); + if (stringvar_map_.end() == itr) + return false; + else + return itr->second.first; + } + } + + inline bool create_variable(const std::string& variable_name, const T& value = T(0)) + { + if (!valid_symbol(variable_name)) + return false; + else if (symbol_exists(variable_name)) + return false; + local_symbol_list_.push_back(value); + T& t = local_symbol_list_.back(); + return add_variable(variable_name,t); + } + inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) { if (!valid_symbol(variable_name)) return false; - else if (symbol_exits(variable_name)) + else if (symbol_exists(variable_name)) return false; else if (1 == variable_name.size()) { @@ -2215,7 +3602,7 @@ namespace exprtk { if (!valid_symbol(function_name)) return false; - else if (symbol_exits(function_name)) + else if (symbol_exists(function_name)) return false; else if (1 == function_name.size()) { @@ -2324,13 +3711,13 @@ namespace exprtk } template class Sequence> - inline std::size_t get_variable_list(Sequence,Allocator>& vlist) + template class Sequence> + inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const { std::size_t count = 0; for (std::size_t i = 0; i < lut_size; ++i) { - variable_pair_t& vp = short_variable_lut_[static_cast(i)]; + const variable_pair_t& vp = short_variable_lut_[static_cast(i)]; if (0 != vp.second) { vlist.push_back(std::make_pair(std::string("")+static_cast(i),vp.second->value())); @@ -2339,8 +3726,8 @@ namespace exprtk } if (!variable_map_.empty()) { - vm_itr_t itr = variable_map_.begin(); - vm_itr_t end = variable_map_.end(); + vm_const_itr_t itr = variable_map_.begin(); + vm_const_itr_t end = variable_map_.end(); while (end != itr) { vlist.push_back(std::make_pair((*itr).first,itr->second.second->ref())); @@ -2351,12 +3738,11 @@ namespace exprtk return count; } - inline bool symbol_exits(const std::string& symbol_name) const + inline bool symbol_exists(const std::string& symbol_name) const { /* - Will return true if either a variable or function - name has already been defined in any of the LUTs - or maps. + Will return true if symbol_name exists as either a + variable or function name in any of the LUTs or maps. */ if ((1 == symbol_name.size()) && short_variable_lut_[static_cast(symbol_name[0])].second) return true; @@ -2372,6 +3758,9 @@ namespace exprtk private: + symbol_table(const symbol_table&); + symbol_table operator=(const symbol_table&); + inline bool valid_symbol(const std::string& symbol) const { if (symbol.empty()) @@ -2399,6 +3788,10 @@ namespace exprtk { short_variable_lut_[i].first = false; short_variable_lut_[i].second = reinterpret_cast(0); + + short_stringvar_lut_[i].first = false; + short_stringvar_lut_[i].second = reinterpret_cast(0); + short_function_lut_[i] = reinterpret_cast(0); } } @@ -2409,8 +3802,15 @@ namespace exprtk function_ptr short_function_lut_[lut_size]; function_map_t function_map_; + stringvar_pair_t short_stringvar_lut_[lut_size]; + stringvar_map_t stringvar_map_; + + std::list local_symbol_list_; + std::list local_stringvar_list_; + std::size_t variable_count_; std::size_t function_count_; + std::size_t stringvar_count_; }; template class parser; @@ -2436,7 +3836,7 @@ namespace exprtk ~expression_holder() { - if (expr && details::expression_node::e_variable != expr->type()) + if (expr && !is_variable_node(expr)) { delete expr; } @@ -2476,7 +3876,7 @@ namespace exprtk return *this; } - inline bool operator!() + inline bool operator!() const { return ((0 == expression_holder_) || (0 == expression_holder_->expr)); } @@ -2487,7 +3887,7 @@ namespace exprtk { if (0 == --expression_holder_->ref_count) { - if (details::expression_node::e_variable != expression_holder_->expr->type()) + if (!is_variable_node(expression_holder_->expr)) { delete expression_holder_; } @@ -2495,12 +3895,12 @@ namespace exprtk } } - inline T operator()() + inline T operator()() const { return value(); } - inline T value() + inline T value() const { if (expression_holder_ && expression_holder_->expr) return expression_holder_->expr->value(); @@ -2508,12 +3908,12 @@ namespace exprtk return std::numeric_limits::quiet_NaN(); } - inline operator T() + inline operator T() const { return value(); } - inline operator bool() + inline operator bool() const { return (T(0) != value()); } @@ -2574,38 +3974,48 @@ namespace exprtk e_level13 }; - typedef ifunction F; - typedef details::expression_node expression_node_t; - typedef details::literal_node literal_node_t; - typedef details::unary_node unary_node_t; - typedef details::binary_node binary_node_t; - typedef details::trinary_node trinary_node_t; - typedef details::quaternary_node quaternary_node_t; - typedef details::quinary_node quinary_node_t; - typedef details::senary_node senary_node_t; - typedef details::conditional_node conditional_node_t; - typedef details::while_loop_node while_loop_node_t; - typedef details::variable_node variable_node_t; - typedef details::sf3_node sf3_node_t; - typedef details::sf4_node sf4_node_t; - typedef details::assignment_node assignment_node_t; - typedef details::function_node function_node_t; - typedef details::token token_t; - typedef expression_node_t* expression_node_ptr; + typedef ifunction F; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::quinary_node quinary_node_t; + typedef details::senary_node senary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::variable_node variable_node_t; + typedef details::stringvar_node stringvar_node_t; + typedef details::assignment_node assignment_node_t; + typedef details::function_node function_node_t; + typedef details::token token_t; + typedef expression_node_t* expression_node_ptr; public: + enum optimization_level + { + e_none = 0, + e_level1 = 1, + e_level2 = 2, + e_level3 = 4, + e_all = 7 + }; + parser() : symbol_table_(0) {} - inline bool compile(const std::string& expression_string, expression& expr) + inline bool compile(const std::string& expression_string, expression& expr, const optimization_level& opt_level = e_all) { if (!validate_expression(expression_string)) { return false; } set_error(""); + expression_generator_.set_optimization_level(opt_level); expression_generator_.set_allocator(node_allocator_); if (!lexer_.process(expression_string)) { @@ -2615,7 +4025,7 @@ namespace exprtk symbol_table_ = expr.get_symbol_table(); next_token(); expression_node_ptr e = parse_expression(); - if ((0 != e) && (current_token_.type == token_t::eof)) + if ((0 != e) && (token_t::eof == current_token_.type)) { expr.set_expression(e); return !(!expr); @@ -2707,7 +4117,7 @@ namespace exprtk case token_t::mul : current_state.set(e_level10,e_level11,details:: e_mul); break; case token_t::mod : current_state.set(e_level10,e_level11,details:: e_mod); break; case token_t::pow : current_state.set(e_level12,e_level12,details:: e_pow); break; - default : if (current_token_.type == token_t::symbol) + default : if (token_t::symbol == current_token_.type) { static const std::string s_and = "and"; static const std::string s_nand = "nand"; @@ -2748,10 +4158,19 @@ namespace exprtk break; next_token(); expr = expression_generator_(current_state.operation,expr,parse_expression(current_state.right)); + if (0 == expr) + { + return expr; + } } return expr; } + static inline expression_node_ptr error_node() + { + return reinterpret_cast(0); + } + template struct scoped_delete { @@ -2775,7 +4194,7 @@ namespace exprtk { for (std::size_t i = 0; i < N; ++i) { - if (p_[i] && details::expression_node::e_variable != p_[i]->type()) + if (p_[i] && !is_variable_node(p_[i])) { parser_.node_allocator_.free(p_[i]); } @@ -2802,7 +4221,7 @@ namespace exprtk next_token(); if (!token_is(token_t::lbracket)) { - return reinterpret_cast(0); + return error_node(); } for (int i = 0; i < static_cast(NumberofParameters); ++i) { @@ -2811,13 +4230,13 @@ namespace exprtk { if (!token_is(token_t::comma)) { - return reinterpret_cast(0); + return error_node(); } } } if (!token_is(token_t::rbracket)) { - return reinterpret_cast(0); + return error_node(); } else result = expression_generator_(opt_type,branch); @@ -2835,7 +4254,7 @@ namespace exprtk next_token(); if (!token_is(token_t::lbracket)) { - return reinterpret_cast(0); + return error_node(); } for (int i = 0; i < static_cast(NumberofParameters); ++i) { @@ -2844,13 +4263,13 @@ namespace exprtk { if (!token_is(token_t::comma)) { - return reinterpret_cast(0); + return error_node(); } } } if (!token_is(token_t::rbracket)) { - return reinterpret_cast(0); + return error_node(); } else result = expression_generator_.function(function,branch); @@ -2860,6 +4279,7 @@ namespace exprtk inline expression_node_ptr parse_conditional_statement() { + //Parse: [if][(][condition][,][consequent][,][alternative][)] expression_node_ptr condition = 0; expression_node_ptr consequent = 0; expression_node_ptr alternative = 0; @@ -2867,40 +4287,41 @@ namespace exprtk if (token_is(token_t::lbracket)) condition = parse_expression(); else - return reinterpret_cast(0); + return error_node(); if (token_is(token_t::comma)) consequent = parse_expression(); else - return reinterpret_cast(0); + return error_node(); if (token_is(token_t::comma)) alternative = parse_expression(); else - return reinterpret_cast(0); + return error_node(); if (token_is(token_t::rbracket)) return expression_generator_.conditional(condition,consequent,alternative); else - return reinterpret_cast(0); + return error_node(); } inline expression_node_ptr parse_while_loop() { + //Parse: [while][(][test expr][)][{][expression][}] expression_node_ptr condition = 0; expression_node_ptr branch = 0; next_token(); if (token_is(token_t::lbracket)) condition = parse_expression(); else - return reinterpret_cast(0); + return error_node(); if (!token_is(token_t::rbracket)) - return reinterpret_cast(0); + return error_node(); if (token_is(token_t::lcrlbracket)) branch = parse_expression(); else - return reinterpret_cast(0); + return error_node(); if (token_is(token_t::rcrlbracket)) return expression_generator_.while_loop(condition,branch); else - return reinterpret_cast(0); + return error_node(); } inline expression_node_ptr parse_special_function(const unsigned int id) @@ -2919,7 +4340,7 @@ namespace exprtk next_token(); if (!token_is(token_t::lbracket)) { - return reinterpret_cast(0); + return error_node(); } for (std::size_t i = 0; i < NumberOfParameters; ++i) { @@ -2928,19 +4349,19 @@ namespace exprtk { if (!token_is(token_t::comma)) { - return reinterpret_cast(0); + return error_node(); } } } if (!token_is(token_t::rbracket)) - return reinterpret_cast(0); + return error_node(); else { switch (NumberOfParameters) { case 3 : result = expression_generator_.special_function(opt_type,branch3); break; case 4 : result = expression_generator_.special_function(opt_type,branch4); break; - default : return reinterpret_cast(0); + default : return error_node(); } } sd3.delete_ptr = false; @@ -2986,21 +4407,21 @@ namespace exprtk if (match_found_error.first) { set_error("parser::parse_branch() - invalid argument count for function: " + match_found_error.second); - return reinterpret_cast(0); + return error_node(); } } - static const std::string s_if = "if"; - static const std::string s_while = "while"; - if (details::imatch(current_token_.value,s_if)) + static const std::string symbol_if = "if"; + static const std::string symbol_while = "while"; + if (details::imatch(current_token_.value,symbol_if)) { return parse_conditional_statement(); } - else if (details::imatch(current_token_.value,s_while)) + else if (details::imatch(current_token_.value,symbol_while)) { return parse_while_loop(); } - else if ((current_token_.value.size() == 4) && '$' == current_token_.value[0] && 'f' == current_token_.value[1]) + else if ((current_token_.value.size() == 4) && '$' == current_token_.value[0] && details::imatch('f',current_token_.value[1])) { unsigned int id = (current_token_.value[2] - '0') * 10 + (current_token_.value[3] - '0'); if (id <= 99) @@ -3008,55 +4429,77 @@ namespace exprtk else { set_error("parser::parse_branch() - invalid special function: " + current_token_.value); - return reinterpret_cast(0); + return error_node(); } } else if (symbol_table_) { const std::string symbol = current_token_.value; + //Are we dealing with a variable or a special constant? expression_node_ptr variable = symbol_table_->get_variable(symbol); if (variable) { - if (symbol_table_->is_constant(symbol)) + if (symbol_table_->is_constant_node(symbol)) { variable = expression_generator_(variable->value()); } next_token(); return variable; } + + //Are we dealing with a string variable? + variable = symbol_table_->get_stringvar(symbol); + if (variable) + { + if (symbol_table_->is_constant_node(symbol)) + { + variable = expression_generator_(dynamic_cast*>(variable)->str()); + } + next_token(); + return variable; + } + + //Are we dealing with a function? ifunction* function = symbol_table_->get_function(symbol); if (function) { expression_node_ptr func_node = reinterpret_cast(0); switch (function->param_count) { - case 0 : func_node = expression_generator_.function(function); break; - case 1 : func_node = parse_function_call<1>(function); break; - case 2 : func_node = parse_function_call<2>(function); break; - case 3 : func_node = parse_function_call<3>(function); break; - case 4 : func_node = parse_function_call<4>(function); break; - case 5 : func_node = parse_function_call<5>(function); break; - case 6 : func_node = parse_function_call<6>(function); break; - case 7 : func_node = parse_function_call<7>(function); break; - case 8 : func_node = parse_function_call<8>(function); break; - case 9 : func_node = parse_function_call<9>(function); break; + case 0 : func_node = expression_generator_.function(function); break; + case 1 : func_node = parse_function_call< 1>(function); break; + case 2 : func_node = parse_function_call< 2>(function); break; + case 3 : func_node = parse_function_call< 3>(function); break; + case 4 : func_node = parse_function_call< 4>(function); break; + case 5 : func_node = parse_function_call< 5>(function); break; + case 6 : func_node = parse_function_call< 6>(function); break; + case 7 : func_node = parse_function_call< 7>(function); break; + case 8 : func_node = parse_function_call< 8>(function); break; + case 9 : func_node = parse_function_call< 9>(function); break; + case 10 : func_node = parse_function_call<10>(function); break; default : { set_error("parser::parse_branch() - invalid number of parameters for function: " + symbol); return expression_node_ptr(0); } } if (func_node) - { return func_node; + else + { + set_error("parser::parse_branch() - failed to generate node for function: " + symbol); + return error_node(); } } - set_error("parser::parse_branch() - undefined variable or function: " + symbol); - return expression_node_ptr(0); + else + { + set_error("parser::parse_branch() - undefined variable or function: " + symbol); + return error_node(); + } } else { set_error("parser::parse_branch() - variable or function detected, yet symbol-table is invalid" + current_token_.value); - return expression_node_ptr(0); + return error_node(); } } @@ -3073,6 +4516,13 @@ namespace exprtk case token_t::symbol : return parse_symbol(); + case token_t::string : + { + expression_node_ptr literal_exp = expression_generator_(current_token_.value); + next_token(); + return literal_exp; + } + case '(' : { next_token(); @@ -3080,7 +4530,7 @@ namespace exprtk if (token_is(token_t::rbracket)) return branch; else - return reinterpret_cast(0); + return error_node(); } case '[' : { @@ -3089,7 +4539,7 @@ namespace exprtk if (token_is(token_t::rsqrbracket)) return branch; else - return reinterpret_cast(0); + return error_node(); } case '{' : { @@ -3098,7 +4548,7 @@ namespace exprtk if (token_is(token_t::rcrlbracket)) return branch; else - return reinterpret_cast(0); + return error_node(); } case '-' : { @@ -3113,12 +4563,12 @@ namespace exprtk case token_t::eof : { set_error("parser::parse_branch() - expected a valid branch [1]"); - return reinterpret_cast(0); + return error_node(); } default : { set_error("parser::parse_branch() - expected a valid branch [2]"); - return reinterpret_cast(0); + return error_node(); } } } @@ -3127,13 +4577,12 @@ namespace exprtk { if (current_token_.type != ttype) { - if (!((current_token_.type == ']') && (token_t::rbracket == ttype))) + if (!((']' == current_token_.type) && (token_t::rbracket == ttype))) { set_error(std::string("parser::token_is() - expected: ") + static_cast(ttype)); return false; } } - next_token(); return true; } @@ -3145,6 +4594,11 @@ namespace exprtk typedef details::expression_node* expression_node_ptr; + inline void set_optimization_level(const optimization_level& optimization_level) + { + optimization_level_ = optimization_level; + } + inline void set_allocator(details::node_allocator& na) { node_allocator_ = &na; @@ -3155,20 +4609,207 @@ namespace exprtk return node_allocator_->allocate(v); } + inline expression_node_ptr operator()(const std::string& s) const + { + return node_allocator_->allocate(s); + } + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1]) { - return synthesize_expression(operation,branch); + if (0 != branch[0]) + return synthesize_expression(operation,branch); + else + return error_node(); } + inline bool valid_string_operation(const details::operator_type& operation) const + { + return (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation); + } + + inline bool operation_optimizable(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_mod == operation) || + (details::e_pow == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation); + } + + inline bool is_level_optimizable(const std::size_t& level = 0) const + { + switch (level) + { + case 1 : return (e_level1 == (optimization_level_ & e_level1)); + case 2 : return (e_level2 == (optimization_level_ & e_level2)); + case 3 : return (e_level2 == (optimization_level_ & e_level2)); + case 0 : return (e_all == (optimization_level_ & e_all)); + default : return false; + } + } + + inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(1)) + return false; + else + return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(1)) + return false; + else + return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); + } + + inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(1)) + return false; + else + return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool vovov1_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(2)) + return false; + else + return (details::is_variable_node(branch[0]) && details::is_vov_node(branch[1])); + } + + inline bool vovov2_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(2)) + return false; + else + return (details::is_vov_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool covov1_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(2)) + return false; + else + return (details::is_constant_node(branch[0]) && details::is_vov_node(branch[1])); + } + + inline bool covov2_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(2)) + return false; + else + return (details::is_cov_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool is_invalid_string_op(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]); + bool b1_string = details::is_string_node(branch[1]) || details::is_const_string_node(branch[1]); + if ((b0_string || b1_string) && !(b0_string && b1_string)) + return true; + if (!valid_string_operation(operation) && b0_string && b1_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]); + bool b1_string = details::is_string_node(branch[1]) || details::is_const_string_node(branch[1]); + return (b0_string && b1_string && valid_string_operation(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 + // to compile this file properly. + #define exprtk_no_extended_optimisations + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if (defined(_MSC_VER) && (_MSC_VER <= 1400)) + #ifndef exprtk_no_extended_optimisations + #define exprtk_no_extended_optimisations + #endif + #endif + #endif + + #ifndef exprtk_no_extended_optimisations + inline bool vovovov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimizable(operation)) + return false; + else if (!is_level_optimizable(3)) + return false; + else + return (details::is_vov_node(branch[0]) && details::is_vov_node(branch[1])); + } + #else + inline bool vovovov_optimizable(const details::operator_type&, expression_node_ptr (&)[2]) const + { + return false; + } + #endif + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - if (details::e_assign == operation) - { - if (details::expression_node::e_variable == branch[0]->type()) - return synthesize_expression(operation,branch); - else - return reinterpret_cast(0); - } + if ((0 == branch[0]) || (0 == branch[1])) + return error_node(); + else if (is_invalid_string_op(operation,branch)) + return error_node(); + else if (details::e_assign == operation) + return synthesize_assignment_expression(operation,branch); + else if (is_string_operation(operation,branch)) + return synthesize_string_expression(operation,branch); + else if (cov_optimizable(operation,branch)) + return synthesize_cov_expression(operation,branch); + else if (voc_optimizable(operation,branch)) + return synthesize_voc_expression(operation,branch); + else if (vov_optimizable(operation,branch)) + return synthesize_vov_expression(operation,branch); + else if (vovov1_optimizable(operation,branch)) + return synthesize_vovov1_expression(operation,branch); + else if (vovov2_optimizable(operation,branch)) + return synthesize_vovov2_expression(operation,branch); + else if (covov1_optimizable(operation,branch)) + return synthesize_covov1_expression(operation,branch); + else if (covov2_optimizable(operation,branch)) + return synthesize_covov2_expression(operation,branch); + else if (vovovov_optimizable(operation,branch)) + return synthesize_vovovov_expression(operation,branch); else return synthesize_expression(operation,branch); } @@ -3202,13 +4843,30 @@ namespace exprtk inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) { expression_node_ptr branch[2] = { b0, b1 }; - if (details::e_assign == operation) - { - if (details::expression_node::e_variable == branch[0]->type()) - return synthesize_expression(operation,branch); - else - return reinterpret_cast(0); - } + if ((0 == b0) || (0 == b1)) + return error_node(); + else if (is_invalid_string_op(operation,branch)) + return error_node(); + else if (details::e_assign == operation) + return synthesize_assignment_expression(operation,branch); + else if (is_string_operation(operation,branch)) + return synthesize_string_expression(operation,branch); + else if (cov_optimizable(operation,branch)) + return synthesize_cov_expression(operation,branch); + else if (voc_optimizable(operation,branch)) + return synthesize_voc_expression(operation,branch); + else if (vov_optimizable(operation,branch)) + return synthesize_vov_expression(operation,branch); + else if (vovov1_optimizable(operation,branch)) + return synthesize_vovov1_expression(operation,branch); + else if (vovov2_optimizable(operation,branch)) + return synthesize_vovov2_expression(operation,branch); + else if (covov1_optimizable(operation,branch)) + return synthesize_covov1_expression(operation,branch); + else if (covov2_optimizable(operation,branch)) + return synthesize_covov2_expression(operation,branch); + else if (vovovov_optimizable(operation,branch)) + return synthesize_vovovov_expression(operation,branch); else return synthesize_expression(operation,branch); } @@ -3217,15 +4875,19 @@ namespace exprtk expression_node_ptr consequent, expression_node_ptr alternative) const { - //Can the condition be immediately evaluated? if so optimise. - if (expression_node_t::e_constant == condition->type()) + //Can the condition be immediately evaluated? if so optimize. + if ((0 == condition) || (0 == consequent) || (0 == alternative)) + return error_node(); + else if (details::is_constant_node(condition)) { - if (condition->value() != Type(0)) + // True branch + if (Type(0) != condition->value()) { node_allocator_->free(condition); node_allocator_->free(alternative); return consequent; } + // False branch else { node_allocator_->free(condition); @@ -3245,32 +4907,90 @@ namespace exprtk inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { - return synthesize_expression(operation,branch); + if (!all_nodes_valid(branch)) + return error_node(); + switch (operation) + { + case details::e_sf00 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf01 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf02 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf03 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf04 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf05 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf06 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf07 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf08 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf09 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf10 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf11 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf12 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf13 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf14 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf15 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf16 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf17 : return node_allocator_->allocate > >(operation,branch); + default : return error_node(); + } } inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { - return synthesize_expression(operation,branch); + if (!all_nodes_valid(branch)) + return error_node(); + switch (operation) + { + case details::e_sf18 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf19 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf20 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf21 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf22 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf23 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf24 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf25 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf26 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf27 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf28 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf29 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf30 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf31 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf32 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf33 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf34 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf35 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf36 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf37 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf38 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf39 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf40 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf41 : return node_allocator_->allocate > >(operation,branch); + case details::e_sf42 : return node_allocator_->allocate > >(operation,branch); + default : return error_node(); + } } template inline expression_node_ptr function(typename function_node_t::ifunction* f, expression_node_ptr (&b)[N]) { expression_node_ptr result = synthesize_expression(f,b); - if (result) + if (0 == result) + return error_node(); + else { + if (!all_nodes_valid(b)) + return error_node(); + else if (N != f->param_count) + return error_node(); function_node_t* func_node_ptr = dynamic_cast(result); if (func_node_ptr) { - func_node_ptr->init_branches(b); + if (func_node_ptr->init_branches(b)) + return result; + else + return error_node(); } else - { - node_allocator_->free(result); - result = reinterpret_cast(0); - } + return error_node(); } - return result; } inline expression_node_ptr function(typename function_node_t::ifunction* f) @@ -3280,18 +5000,15 @@ namespace exprtk private: - template - inline bool is_contant_node(NodePtr n) const - { - return (expression_node_t::e_constant == n->type()); - } - template inline bool is_constant_foldable(NodePtr (&b)[N]) const { for (std::size_t i = 0; i < N; ++i) { - if (b[i] && !is_contant_node(b[i])) return false; + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; } return true; } @@ -3306,12 +5023,493 @@ namespace exprtk return true; } + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + return synthesize_expression(operation,branch); + else + return error_node(); + } + + inline expression_node_ptr synthesize_cov_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T c = dynamic_cast* >(branch[0])->value(); + T& v = dynamic_cast*>(branch[1])->ref(); + node_allocator_->free(branch[0]); + switch (operation) + { + case details::e_add : return node_allocator_->allocate_cr > >(c,v); + case details::e_sub : return node_allocator_->allocate_cr > >(c,v); + case details::e_mul : return node_allocator_->allocate_cr > >(c,v); + case details::e_div : return node_allocator_->allocate_cr > >(c,v); + case details::e_mod : return node_allocator_->allocate_cr > >(c,v); + case details::e_pow : return node_allocator_->allocate_cr > >(c,v); + case details::e_lt : return node_allocator_->allocate_cr > >(c,v); + case details::e_lte : return node_allocator_->allocate_cr > >(c,v); + case details::e_gt : return node_allocator_->allocate_cr > >(c,v); + case details::e_gte : return node_allocator_->allocate_cr > >(c,v); + case details::e_eq : return node_allocator_->allocate_cr > >(c,v); + case details::e_ne : return node_allocator_->allocate_cr > >(c,v); + case details::e_and : return node_allocator_->allocate_cr > >(c,v); + case details::e_nand : return node_allocator_->allocate_cr > >(c,v); + case details::e_or : return node_allocator_->allocate_cr > >(c,v); + case details::e_nor : return node_allocator_->allocate_cr > >(c,v); + case details::e_xor : return node_allocator_->allocate_cr > >(c,v); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_voc_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T& v = dynamic_cast*>(branch[0])->ref(); + T c = dynamic_cast* >(branch[1])->value(); + node_allocator_->free(branch[1]); + switch (operation) + { + case details::e_add : return node_allocator_->allocate_rc > >(v,c); + case details::e_sub : return node_allocator_->allocate_rc > >(v,c); + case details::e_mul : return node_allocator_->allocate_rc > >(v,c); + case details::e_div : return node_allocator_->allocate_rc > >(v,c); + case details::e_mod : return node_allocator_->allocate_rc > >(v,c); + case details::e_pow : return node_allocator_->allocate_rc > >(v,c); + case details::e_lt : return node_allocator_->allocate_rc > >(v,c); + case details::e_lte : return node_allocator_->allocate_rc > >(v,c); + case details::e_gt : return node_allocator_->allocate_rc > >(v,c); + case details::e_gte : return node_allocator_->allocate_rc > >(v,c); + case details::e_eq : return node_allocator_->allocate_rc > >(v,c); + case details::e_ne : return node_allocator_->allocate_rc > >(v,c); + case details::e_and : return node_allocator_->allocate_rc > >(v,c); + case details::e_nand : return node_allocator_->allocate_rc > >(v,c); + case details::e_or : return node_allocator_->allocate_rc > >(v,c); + case details::e_nor : return node_allocator_->allocate_rc > >(v,c); + case details::e_xor : return node_allocator_->allocate_rc > >(v,c); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_vov_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + Type& v1 = dynamic_cast*>(branch[0])->ref(); + Type& v2 = dynamic_cast*>(branch[1])->ref(); + switch (operation) + { + case details::e_add : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_sub : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_mul : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_div : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_mod : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_pow : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_lt : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_lte : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_gt : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_gte : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_eq : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_ne : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_and : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_nand : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_or : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_nor : return node_allocator_->allocate_rr > >(v1,v2); + case details::e_xor : return node_allocator_->allocate_rr > >(v1,v2); + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_vovov1_expression_impl(Type& v0, expression_node_ptr node) + { + details::operator_type op = dynamic_cast*>(node)->operation(); + switch (op) + { + case details::e_add : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_sub : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_mul : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_div : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_mod : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_pow : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_lt : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_lte : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_gt : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_gte : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_eq : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_ne : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_and : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_nand : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_or : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_nor : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + case details::e_xor : return node_allocator_->allocate_rr > >(v0,(*dynamic_cast >*>(node))); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_vovov1_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T& v0 = dynamic_cast*>(branch[0])->ref(); + expression_node_ptr result = error_node(); + switch (operation) + { + case details::e_add : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_sub : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_mul : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_div : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_mod : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_pow : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_lt : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_lte : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_gt : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_gte : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_eq : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_ne : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_and : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_nand : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_or : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_nor : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + case details::e_xor : result = synthesize_vovov1_expression_impl >(v0,branch[1]); break; + default : return error_node(); + } + node_allocator_->free(branch[1]); + return result; + } + + template + inline expression_node_ptr synthesize_vovov2_expression_impl(T& v0, expression_node_ptr node) + { + details::operator_type op = dynamic_cast*>(node)->operation(); + switch (op) + { + case details::e_add : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_sub : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_mul : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_div : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_mod : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_pow : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_lt : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_lte : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_gt : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_gte : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_eq : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_ne : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_and : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_nand : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_or : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_nor : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + case details::e_xor : return node_allocator_->allocate_rr,Operation1> >((*dynamic_cast >*>(node)),v0); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_vovov2_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T& v0 = dynamic_cast*>(branch[1])->ref(); + expression_node_ptr result = error_node(); + switch (operation) + { + case details::e_add : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_sub : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_mul : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_div : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_mod : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_pow : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_lt : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_lte : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_gt : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_gte : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_eq : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_ne : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_and : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_nand : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_or : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_nor : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + case details::e_xor : result = synthesize_vovov2_expression_impl >(v0,branch[0]); break; + default : return error_node(); + } + node_allocator_->free(branch[0]); + return result; + } + + template + inline expression_node_ptr synthesize_covov1_expression_impl(const T& c, expression_node_ptr node) + { + details::operator_type op = dynamic_cast*>(node)->operation(); + switch (op) + { + case details::e_add : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_sub : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_mul : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_div : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_mod : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_pow : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_lt : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_lte : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_gt : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_gte : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_eq : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_ne : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_and : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_nand : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_or : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_nor : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + case details::e_xor : return node_allocator_->allocate_rr > >(c,(*dynamic_cast >*>(node))); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_covov1_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T c = dynamic_cast*>(branch[0])->value(); + expression_node_ptr result = error_node(); + switch (operation) + { + case details::e_add : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_sub : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_mul : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_div : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_mod : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_pow : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_lt : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_lte : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_gt : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_gte : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_eq : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_ne : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_and : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_nand : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_or : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_nor : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + case details::e_xor : result = synthesize_covov1_expression_impl >(c,branch[1]); break; + default : return error_node(); + } + node_allocator_->free(branch[1]); + return result; + } + + template + inline expression_node_ptr synthesize_covov2_expression_impl(expression_node_ptr node, T& v) + { + details::operator_type op = dynamic_cast*>(node)->operation(); + switch (op) + { + case details::e_add : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_sub : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_mul : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_div : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_mod : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_pow : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_lt : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_lte : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_gt : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_gte : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_eq : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_ne : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_and : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_nand : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_or : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_nor : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + case details::e_xor : return node_allocator_->allocate_rr,Operation2> >((*dynamic_cast >*>(node)),v); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_covov2_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + T& v = dynamic_cast*>(branch[1])->ref(); + expression_node_ptr result = error_node(); + switch (operation) + { + case details::e_add : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_sub : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_mul : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_div : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_mod : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_pow : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_lt : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_lte : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_gt : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_gte : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_eq : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_ne : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_and : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_nand : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_or : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_nor : result = synthesize_covov2_expression_impl >(branch[0],v); break; + case details::e_xor : result = synthesize_covov2_expression_impl >(branch[0],v); break; + default : return error_node(); + } + node_allocator_->free(branch[0]); + return result; + } + + #ifndef exprtk_no_extended_optimisations + template + inline expression_node_ptr synthesize_vovovov_expression_impl2(expression_node_ptr (&node)[2]) + { + details::operator_type op = dynamic_cast*>(node[1])->operation(); + switch (op) + { + case details::e_add : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_sub : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_mul : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_div : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_mod : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_pow : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_lt : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_lte : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_gt : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_gte : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_eq : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_ne : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_and : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_nand : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_or : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_nor : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + case details::e_xor : return node_allocator_->allocate_rr > >((*dynamic_cast*>(node[0])),(*dynamic_cast >*>(node[1]))); + default : return error_node(); + } + #else + template + inline expression_node_ptr synthesize_vovovov_expression_impl2(expression_node_ptr (&)[2]) + { + return error_node(); + #endif + } + + #ifndef exprtk_no_extended_optimisations + template + inline expression_node_ptr synthesize_vovovov_expression_impl1(expression_node_ptr (&node)[2]) + { + details::operator_type op = dynamic_cast*>(node[0])->operation(); + switch (op) + { + case details::e_add : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_sub : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_mul : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_div : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_mod : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_pow : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_lt : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_lte : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_gt : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_gte : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_eq : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_ne : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_and : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_nand : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_or : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_nor : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + case details::e_xor : return synthesize_vovovov_expression_impl2, Operation2>(node); break; + default : return error_node(); + } + #else + template + inline expression_node_ptr synthesize_vovovov_expression_impl1(expression_node_ptr (&)[2]) + { + return error_node(); + #endif + } + + #ifndef exprtk_no_extended_optimisations + inline expression_node_ptr synthesize_vovovov_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + switch (opr) + { + case details::e_add : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_sub : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_mul : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_div : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_mod : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_pow : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_lt : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_lte : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_gt : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_gte : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_eq : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_ne : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_and : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_nand : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_or : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_nor : result = synthesize_vovovov_expression_impl1 >(branch); break; + case details::e_xor : result = synthesize_vovovov_expression_impl1 >(branch); break; + default : return error_node(); + } + node_allocator_->free(branch[0]); + node_allocator_->free(branch[1]); + return result; + } + #else + inline expression_node_ptr synthesize_vovovov_expression(const details::operator_type&, expression_node_ptr (&)[2]) + { + return error_node(); + } + #endif + + template + inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) + { + switch (opr) + { + case details::e_lt : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + case details::e_lte : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + case details::e_gt : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + case details::e_gte : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + case details::e_eq : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + case details::e_ne : return node_allocator_->allocate_tt >,T0,T1>(s0,s1); + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = dynamic_cast*>(branch[0])->ref(); + std::string& s1 = dynamic_cast*>(branch[1])->ref(); + return synthesize_sos_expression_impl(opr,s0,s1); + } + + inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = dynamic_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = dynamic_cast*>(branch[1])->str(); + return synthesize_sos_expression_impl(opr,s0,s1); + } + + inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = dynamic_cast*>(branch[0])->str(); + std::string& s1 = dynamic_cast< details::stringvar_node*>(branch[1])->ref(); + return synthesize_sos_expression_impl(opr,s0,s1); + } + + 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(); + expression_node_ptr temp = synthesize_sos_expression_impl(opr,s0,s1); + Type v = temp->value(); + expression_node_ptr result = node_allocator_->allocate(v); + node_allocator_->free(temp); + return result; + } + + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + if (details::is_string_node(branch[0])) + { + if (details::is_string_node(branch[1])) return synthesize_sos_expression(opr,branch); + else if (details::is_const_string_node(branch[1])) return synthesize_socs_expression(opr,branch); + } + else if (details::is_const_string_node(branch[0])) + { + if (details::is_string_node(branch[1])) return synthesize_csos_expression(opr,branch); + else if (details::is_const_string_node(branch[1])) return synthesize_csocs_expression(opr,branch); + } + return error_node(); + } + template inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) { if ((details::e_default != operation) && all_nodes_valid(branch)) { - //Attempt simple constant folding optimisation. + //Attempt simple constant folding optimization. expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); if (is_constant_foldable(branch)) { @@ -3323,7 +5521,7 @@ namespace exprtk return expression_point; } else - return reinterpret_cast(0); + return error_node(); } template @@ -3331,7 +5529,7 @@ namespace exprtk { if (all_nodes_valid(branch)) { - //Attempt simple constant folding optimisation. + //Attempt simple constant folding optimization. expression_node_ptr expression_point = node_allocator_->allocate(f); dynamic_cast(expression_point)->init_branches(branch); if (is_constant_foldable(branch)) @@ -3344,10 +5542,95 @@ namespace exprtk return expression_point; } else - return reinterpret_cast(0); + return error_node(); } details::node_allocator* node_allocator_; + optimization_level optimization_level_; + }; + + template + class expression_optimizer + { + public: + + typedef details::expression_node* expression_node_ptr; + + inline void set_allocator(details::node_allocator& na) + { + node_allocator_ = &na; + } + + inline void process(expression_node_ptr expr) + { + std::deque node_list; + node_list.push_back(expr); + expression_node_ptr node = reinterpret_cast(0); + while (!node_list.empty()) + { + node = node_list.front(); + node_list.pop_front(); + if (details::is_constant_node(node) || details::is_variable_node(node)) + continue; + else if (details::is_binary_node(node) && bn_type0_optimizable(node)) + perform_bn_type0_optimization(node); + else + add_sub_branches(node,node_list); + } + } + + private: + + template class Sequence> + void add_sub_branches(expression_node_ptr node, Sequence& seq) + { + if (details::is_unary_node(node)) + seq.push_back(node->branch(0)); + else if (details::is_binary_node(node)) + { + seq.push_back(node->branch(0)); + seq.push_back(node->branch(1)); + } + } + + inline bool operation_optimizable(const details::operator_type& operation) const + { + return (details::e_add == operation) || (details::e_sub == operation) || + (details::e_mul == operation) || (details::e_div == operation) || + (details::e_mod == operation) || (details::e_pow == operation) || + (details::e_lt == operation) || (details::e_lte == operation) || + (details::e_gt == operation) || (details::e_gte == operation) || + (details::e_eq == operation) || (details::e_ne == operation) || + (details::e_and == operation) || (details::e_nand == operation) || + (details::e_or == operation) || (details::e_nor == operation) || + (details::e_xor == operation); + } + + inline bool bn_type0_optimizable(const expression_node_ptr expr) const + { + const details::binary_node* node = dynamic_cast*>(expr); + if (0 == node) + return false; + if (!operation_optimizable(node->operation())) + return false; + expression_node_ptr b0 = node->branch(0); + expression_node_ptr b1 = node->branch(1); + if (details::is_variable_node(b0) && (details::is_variable_node(b1) || details::is_constant_node(b1))) + return true; + if (details::is_constant_node(b0) && (details::is_variable_node(b1) || details::is_constant_node(b1))) + return true; + return false; + } + + inline void perform_bn_type0_optimization(const expression_node_ptr) + { + } + + private: + + details::node_allocator* node_allocator_; + }; inline bool check0(const char c0, const char c1, @@ -3371,8 +5654,8 @@ namespace exprtk return false; } + //Check for certain illegal sequences of characters. std::stack bracket_stack; - for (std::size_t i = 0; i < (expression_string.size() - 1); ++i) { char c0 = expression_string[i]; @@ -3383,46 +5666,26 @@ namespace exprtk return false; } else if ( - check0(c0,c1,'*','*','/') || - check0(c0,c1,'*','%','^') || - check0(c0,c1,'/','*','/') || - check0(c0,c1,'/','%','^') || - check0(c0,c1,'+','*','/') || - check0(c0,c1,'+','%','^') || - check0(c0,c1,'-','*','/') || - check0(c0,c1,'-','%','^') || - check0(c0,c1,'^','*','/') || - check0(c0,c1,'^','^','%') || - check0(c0,c1,'%','*','/') || - check0(c0,c1,'%','^','%') || - check0(c0,c1,'.','%','^') || - check0(c0,c1,'.','*','/') || - check0(c0,c1,',','%','^') || - check0(c0,c1,',','*','/') || - check0(c0,c1,'(','*','/') || - check0(c0,c1,'(','%','^') || - check0(c0,c1,'[','*','/') || - check0(c0,c1,'[','%','^') || - check0(c0,c1,'{','*','/') || - check0(c0,c1,'{','%','^') || - check0(c0,c1,'+',')',']') || - check0(c0,c1,'-',')',']') || - check0(c0,c1,'*',')',']') || - check0(c0,c1,'/',')',']') || - check0(c0,c1,'^',')',']') || - check0(c0,c1,'%',')',']') || - check1(c0,c1,'+','}' ) || - check1(c0,c1,'-','}' ) || - check1(c0,c1,'*','}' ) || - check1(c0,c1,'/','}' ) || - check1(c0,c1,'^','}' ) || - check1(c0,c1,'%','}' ) || - check1(c0,c1,'.','.' ) || - check1(c0,c1,'.','+' ) || - check1(c0,c1,'.','-' ) || - check1(c0,c1,'.','*' ) || - check1(c0,c1,'.','/' ) || - check1(c0,c1,',',',' ) + check0(c0,c1,'*','*','/') || check0(c0,c1,'*','%','^') || + check0(c0,c1,'/','*','/') || check0(c0,c1,'/','%','^') || + check0(c0,c1,'+','*','/') || check0(c0,c1,'+','%','^') || + check0(c0,c1,'-','*','/') || check0(c0,c1,'-','%','^') || + check0(c0,c1,'^','*','/') || check0(c0,c1,'^','^','%') || + check0(c0,c1,'%','*','/') || check0(c0,c1,'%','^','%') || + check0(c0,c1,'.','%','^') || check0(c0,c1,'.','*','/') || + check0(c0,c1,',','%','^') || check0(c0,c1,',','*','/') || + check0(c0,c1,'(','*','/') || check0(c0,c1,'(','%','^') || + check0(c0,c1,'[','*','/') || check0(c0,c1,'[','%','^') || + check0(c0,c1,'{','*','/') || check0(c0,c1,'{','%','^') || + check0(c0,c1,'+',')',']') || check0(c0,c1,'-',')',']') || + check0(c0,c1,'*',')',']') || check0(c0,c1,'/',')',']') || + check0(c0,c1,'^',')',']') || check0(c0,c1,'%',')',']') || + check1(c0,c1,'+','}' ) || check1(c0,c1,'-','}' ) || + check1(c0,c1,'*','}' ) || check1(c0,c1,'/','}' ) || + check1(c0,c1,'^','}' ) || check1(c0,c1,'%','}' ) || + check1(c0,c1,'.','.' ) || check1(c0,c1,'.','+' ) || + check1(c0,c1,'.','-' ) || check1(c0,c1,'.','*' ) || + check1(c0,c1,'.','/' ) || check1(c0,c1,',',',' ) ) { set_error(std::string("parser::validate_expression() - invalid character combination: ") + expression_string.substr(i,2)); @@ -3488,6 +5751,7 @@ namespace exprtk details::token current_token_; details::token store_current_token_; expression_generator expression_generator_; + expression_optimizer expression_optimizer_; details::node_allocator node_allocator_; symbol_table* symbol_table_; std::string error_description_; @@ -3519,7 +5783,10 @@ namespace exprtk const T& r0, const T& r1, const std::size_t number_of_intervals = 1000000) { - details::variable_node* var = e.get_symbol_table()->get_variable(variable_name); + symbol_table* sym_table = e.get_symbol_table(); + if (0 == sym_table) + return std::numeric_limits::quiet_NaN(); + details::variable_node* var = sym_table->get_variable(variable_name); if (var) { T& x = var->ref(); @@ -3552,7 +5819,10 @@ namespace exprtk const std::string& variable_name, const double& h = 0.00001) { - details::variable_node* var = e.get_symbol_table()->get_variable(variable_name); + symbol_table* sym_table = e.get_symbol_table(); + if (0 == sym_table) + return std::numeric_limits::quiet_NaN(); + details::variable_node* var = sym_table->get_variable(variable_name); if (var) { T& x = var->ref(); @@ -3561,11 +5831,121 @@ namespace exprtk else return std::numeric_limits::quiet_NaN(); } +} + +#ifdef WIN32 + #ifndef NOMINMAX + #define NOMINMAX + #endif + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include +#else + #include + #include +#endif + +namespace exprtk +{ + + class timer + { + public: + + #ifdef WIN32 + timer() + : in_use_(false) + { + QueryPerformanceFrequency(&clock_frequency_); + } + + inline void start() + { + in_use_ = true; + QueryPerformanceCounter(&start_time_); + } + + inline void stop() + { + QueryPerformanceCounter(&stop_time_); + in_use_ = false; + } + + inline double time() const + { + return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); + } + + #else + + timer() + : in_use_(false) + { + start_time_.tv_sec = 0; + start_time_.tv_usec = 0; + stop_time_.tv_sec = 0; + stop_time_.tv_usec = 0; + } + + inline void start() + { + in_use_ = true; + gettimeofday(&start_time_,0); + } + + inline void stop() + { + gettimeofday(&stop_time_, 0); + in_use_ = false; + } + + inline unsigned long long int usec_time() const + { + if (!in_use_) + { + if (stop_time_.tv_sec >= start_time_.tv_sec) + { + return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) + + (stop_time_.tv_usec - start_time_.tv_usec); + } + else + return std::numeric_limits::max(); + } + else + return std::numeric_limits::max(); + } + + inline double time() const + { + return usec_time() * 0.000001; + } + + #endif + + inline bool in_use() const + { + return in_use_; + } + + private: + + bool in_use_; + + #ifdef WIN32 + LARGE_INTEGER start_time_; + LARGE_INTEGER stop_time_; + LARGE_INTEGER clock_frequency_; + #else + struct timeval start_time_; + struct timeval stop_time_; + #endif + }; namespace information { static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.718281828"; + static const char* version = "2.718281828459"; static const char* date = "20111111"; static inline std::string data() diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 6693416..082f122 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -27,6 +27,8 @@ typedef std::pair test_t; static const test_t test_list[] = { + // Note: The each of following tests should + // all compile down to a single literal node. test_t("0",0.0), test_t("1",1.0), test_t("2",2.0), @@ -37,6 +39,11 @@ static const test_t test_list[] = test_t("7",7.0), test_t("8",8.0), test_t("9",9.0), + test_t("12.12",12.12), + test_t("123.123",123.123), + test_t("1234.1234",1234.1234), + test_t("12345.12345",12345.12345), + test_t("123456.123456",123456.123456), test_t("0.0",0.0), test_t("1.0",1.0), test_t("2.0",2.0), @@ -666,7 +673,7 @@ static const test_t test_list[] = static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t); -template +template inline bool not_equal(const T& t1, const T& t2, const T& epsilon = 0.0000000001/*std::numeric_limits::epsilon()*/) @@ -676,7 +683,7 @@ inline bool not_equal(const T& t1, return std::abs(t1 - t2) > (std::max(T(1.0),std::max(std::abs(t1),std::abs(t2))) * epsilon); } -template +template inline bool test_expression(const std::string& expression_string, const T& expected_result) { exprtk::expression expression; @@ -707,10 +714,10 @@ inline bool test_expression(const std::string& expression_string, const T& expec return true; } -template +template inline bool run_test0() { - const std::size_t rounds = 10000; + const std::size_t rounds = 100; for (std::size_t r = 0; r < rounds; ++r) { for (std::size_t i = 0; i < test_list_size; ++i) @@ -722,8 +729,112 @@ inline bool run_test0() return true; } + template +struct test_xy +{ + test_xy(std::string e, const T& v0, const T& v1, const T& r) + : expr(e), + x(v0), + y(v1), + result(r) + {} + + std::string expr; + T x; + T y; + T result; +}; + +template inline bool run_test1() +{ + static const test_xy test_list[] = + { + test_xy("x + y" ,T(2.2),T(3.3),T(5.5 )), + test_xy("x - y" ,T(3.3),T(2.2),T(1.1 )), + test_xy("x * y" ,T(3.3),T(2.2),T(7.26 )), + test_xy("x / y" ,T(3.3),T(2.2),T(1.5 )), + test_xy("(x + y) * (x + y)" ,T(2.2),T(3.3),T(30.25)), + test_xy("(x + y) / (x + y)" ,T(2.2),T(3.3),T(1.0 )), + test_xy("x + y > x and x + y > y" ,T(2.2),T(3.3),T(1.0)), + test_xy("1 + (x + y)" ,T(2.2),T(3.3),T(6.5 )), + test_xy("(x + y) - 1" ,T(2.2),T(3.3),T(4.5 )), + test_xy("1 + (x + y) * 2" ,T(2.2),T(3.3),T(12.0 )), + test_xy("2 * (x + y) - 1" ,T(2.2),T(3.3),T(10.0 )), + test_xy("y + (x + 1)" ,T(2.2),T(3.3),T(6.5 )), + test_xy("(x + 1) + y" ,T(2.2),T(3.3),T(6.5 )), + test_xy("2 * x" ,T(2.2),T(0.0),T(4.4)), + test_xy("x * 2" ,T(2.2),T(0.0),T(4.4)), + test_xy("1.1 + x",T(2.2),T(0.0),T(3.3)), + test_xy("x + 1.1",T(2.2),T(0.0),T(3.3)), + test_xy("x * 1 == x" ,T(2.0),T(3.0),T(1.0)), + test_xy("1 * x == x" ,T(2.0),T(3.0),T(1.0)), + test_xy("y * 1 == y" ,T(2.0),T(3.0),T(1.0)), + test_xy("1 * y == y" ,T(2.0),T(3.0),T(1.0)), + test_xy("x * 0 == 0" ,T(2.0),T(3.0),T(1.0)), + test_xy("0 * x == 0" ,T(2.0),T(3.0),T(1.0)), + test_xy("y * 0 == 0" ,T(2.0),T(3.0),T(1.0)), + test_xy("0 * y == 0" ,T(2.0),T(3.0),T(1.0)), + test_xy("x + 1 == 1 + x",T(2.0),T(3.0),T(1.0)), + test_xy("y + 1 == 1 + y",T(2.0),T(3.0),T(1.0)), + test_xy("x + y == y + x",T(2.0),T(3.0),T(1.0)), + test_xy("x * y == y * x",T(2.0),T(3.0),T(1.0)), + test_xy("x < y" ,T(2.0),T(3.0),T(1.0)), + test_xy("y > x" ,T(2.0),T(3.0),T(1.0)), + test_xy("x <= y" ,T(2.0),T(3.0),T(1.0)), + test_xy("y >= x" ,T(2.0),T(3.0),T(1.0)), + test_xy("x + y > y" ,T(2.0),T(3.0),T(1.0)), + test_xy("x + y > x" ,T(2.0),T(3.0),T(1.0)), + test_xy("x * y > y" ,T(2.0),T(3.0),T(1.0)), + test_xy("x * y > x" ,T(2.0),T(3.0),T(1.0)), + test_xy("(x + y) > y" ,T(2.0),T(3.0),T(1.0)), + test_xy("(x + y) > x" ,T(2.0),T(3.0),T(1.0)), + test_xy("(x * y) > y" ,T(2.0),T(3.0),T(1.0)), + test_xy("(x * y) > x" ,T(2.0),T(3.0),T(1.0)) + }; + + static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy); + + const std::size_t rounds = 10000; + for (std::size_t r = 0; r < rounds; ++r) + { + for (std::size_t i = 0; i < test_list_size; ++i) + { + test_xy& test = const_cast&>(test_list[i]); + + exprtk::symbol_table symbol_table; + symbol_table.add_variable("x",test.x); + symbol_table.add_variable("y",test.y); + + exprtk::expression expression; + expression.register_symbol_table(symbol_table); + + { + exprtk::parser parser; + if (!parser.compile(test.expr,expression)) + { + std::cout << "test_expression() - Error: " << parser.error() << "\tExpression: " << test.expr << std::endl; + return false; + } + } + + T result = expression.value(); + if (not_equal(result,test.result)) + { + printf("Computation Error: Expression: [%s]\tExpected: %19.15f\tResult: %19.15f\n", + test.expr.c_str(), + test.result, + result); + return false; + } + } + } + return true; +} + +template +inline bool run_test2() { std::string expression_string = "a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+" "A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+" @@ -761,41 +872,46 @@ inline bool run_test1() static const std::size_t variable_list_size = sizeof(variable_list) / sizeof(std::string); - exprtk::expression expression; - exprtk::symbol_table symbol_table; + static const std::size_t rounds = 10000; - std::vector v; - v.resize(variable_list_size); - - for (std::size_t i = 0; i < variable_list_size; ++i) + for (std::size_t r = 0; r < rounds; ++r) { - v[i] = i; - symbol_table.add_variable(variable_list[i],v[i]); + exprtk::expression expression; + exprtk::symbol_table symbol_table; + + std::vector v; + v.resize(variable_list_size); + + for (std::size_t i = 0; i < variable_list_size; ++i) + { + v[i] = i; + symbol_table.add_variable(variable_list[i],v[i]); + } + + symbol_table.add_constants(); + + expression.register_symbol_table(symbol_table); + + exprtk::parser parser; + + if (!parser.compile(expression_string,expression)) + { + std::cout << "run_test1() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl; + return false; + } + expression.value(); } - - symbol_table.add_constants(); - - expression.register_symbol_table(symbol_table); - - exprtk::parser parser; - - if (!parser.compile(expression_string,expression)) - { - std::cout << "run_test1() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl; - return false; - } - expression.value(); return true; } -template +template inline T clamp(const T& l, const T& v, const T& u) { return (v < l) ? l : ((v > u) ? u : v); } -template -inline bool run_test2() +template +inline bool run_test3() { std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(y / 2 * pi),+1.0)"; @@ -822,6 +938,7 @@ inline bool run_test2() } const T pi = T(3.14159265358979323846); + const T increment = T(0.0001); while ((x <= T(+1000.0)) && (y <= T(+1000.0))) { @@ -837,14 +954,14 @@ inline bool run_test2() y); return false; } - x += 0.001; - y += 0.001; + x += increment; + y += increment; } return true; } -template -inline bool run_test3() +template +inline bool run_test4() { typedef exprtk::expression expression_t; std::string expression_string = "clamp(-1.0,sin(2 * pi * x_var123) + cos(y_var123 / 2 * pi),+1.0)"; @@ -875,6 +992,7 @@ inline bool run_test3() } const T pi = T(3.14159265358979323846); + const T increment = T(0.0001); while ((x <= T(+1000.0)) && (y <= T(+1000.0))) { @@ -896,14 +1014,14 @@ inline bool run_test3() return false; } } - x += 0.001; - y += 0.001; + x += increment; + y += increment; } return true; } -template -inline bool run_test4() +template +inline bool run_test5() { typedef exprtk::expression expression_t; std::string expression_string = "sqrt(1 - (x^2))"; @@ -944,11 +1062,11 @@ inline bool run_test4() return true; } -template -inline bool run_test5() +template +inline bool run_test6() { typedef exprtk::expression expression_t; - std::string expression_string = "sin(2*x)"; + std::string expression_string = "sin(2x+1/3)"; T x = T(0.0); @@ -970,7 +1088,7 @@ inline bool run_test5() { T result1 = exprtk::derivative(expression,x); T result2 = exprtk::derivative(expression,"x"); - T real_result = T(2.0) * std::cos(T(2.0) * x); + T real_result = T(2.0) * std::cos(T(2.0) * x + T(1.0/3.0)); if (not_equal(result1,result2,0.000000001)) { @@ -989,8 +1107,8 @@ inline bool run_test5() return true; } -template -inline bool run_test6() +template +inline bool run_test7() { static const std::string expr_str[] = @@ -1021,6 +1139,13 @@ inline bool run_test6() "avg(x,y,z,w)", "avg(x,y,z,w,u)", "(u := u <- min(x:=1,y:=2,z:=3)) == 1", + "(2x+3y+4z+5w)==(2*x+3*y+4*z+5*w)", + "(3(x+y)/2+1)==(3*(x+y)/2+1)", + "((x+y)3+1/4)==((x+y)*3+1/4)", + "((x+y)z+1/2)==((x+y)*z+1/2)", + "(3min(x,y))==(3*min(x,y))", + "(sin(x)y)==(sin(x)*y)", + "(sin(x)cos(y)+1)==(sin(x)*cos(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))", @@ -1103,7 +1228,7 @@ inline bool run_test6() return true; } -template +template struct myfunc : public exprtk::ifunction { myfunc() : exprtk::ifunction(2) {} @@ -1114,8 +1239,8 @@ struct myfunc : public exprtk::ifunction } }; -template -inline bool run_test7() +template +inline bool run_test8() { static const std::size_t rounds = 100000; for (std::size_t i = 0; i < rounds; ++i) @@ -1164,16 +1289,16 @@ inline bool run_test7() const T pi = T(3.14159265358979323846); T result = expression.value(); - T expected = mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2) + - mf(sin(x*pi),y/2); + T expected = mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0); if (not_equal(result,expected,0.0000001)) { @@ -1196,7 +1321,8 @@ int main() run_test4() && run_test5() && run_test6() && - run_test7() + run_test7() && + run_test8() ) ? 0 : 1; } diff --git a/readme.txt b/readme.txt index 18833ca..59b52e3 100644 --- a/readme.txt +++ b/readme.txt @@ -46,3 +46,4 @@ Expression Library can be found at: (01) readme.txt (02) exprtk.hpp (03) exprtk_test.cpp +(04) exprtk_benchmark.cpp