| /* |
| ****************************************************************** |
| * C++ Mathematical Expression Toolkit Library * |
| * * |
| * Author: Arash Partow (1999-2016) * |
| * 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) (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) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * |
| * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * |
| * * |
| ****************************************************************** |
| */ |
| |
| |
| #ifndef INCLUDE_EXPRTK_HPP |
| #define INCLUDE_EXPRTK_HPP |
| |
| |
| #include <algorithm> |
| #include <cctype> |
| #include <cmath> |
| #include <complex> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| #include <deque> |
| #include <exception> |
| #include <functional> |
| #include <iterator> |
| #include <limits> |
| #include <list> |
| #include <map> |
| #include <set> |
| #include <stack> |
| #include <stdexcept> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| |
| namespace exprtk |
| { |
| #ifdef exprtk_enable_debugging |
| #define exprtk_debug(params) printf params |
| #else |
| #define exprtk_debug(params) (void)0 |
| #endif |
| |
| namespace details |
| { |
| typedef unsigned char uchar_t; |
| typedef char char_t; |
| |
| inline bool is_whitespace(const char_t c) |
| { |
| return (' ' == c) || ('\n' == c) || |
| ('\r' == c) || ('\t' == c) || |
| ('\b' == c) || ('\v' == c) || |
| ('\f' == c) ; |
| } |
| |
| inline bool is_operator_char(const char_t c) |
| { |
| return ('+' == c) || ('-' == c) || |
| ('*' == c) || ('/' == c) || |
| ('^' == c) || ('<' == c) || |
| ('>' == c) || ('=' == c) || |
| (',' == c) || ('!' == c) || |
| ('(' == c) || (')' == c) || |
| ('[' == c) || (']' == c) || |
| ('{' == c) || ('}' == c) || |
| ('%' == c) || (':' == c) || |
| ('?' == c) || ('&' == c) || |
| ('|' == c) || (';' == c) ; |
| } |
| |
| inline bool is_letter(const char_t c) |
| { |
| return (('a' <= c) && (c <= 'z')) || |
| (('A' <= c) && (c <= 'Z')) ; |
| } |
| |
| inline bool is_digit(const char_t c) |
| { |
| return ('0' <= c) && (c <= '9'); |
| } |
| |
| inline bool is_letter_or_digit(const char_t c) |
| { |
| return is_letter(c) || is_digit(c); |
| } |
| |
| inline bool is_left_bracket(const char_t c) |
| { |
| return ('(' == c) || ('[' == c) || ('{' == c); |
| } |
| |
| inline bool is_right_bracket(const char_t c) |
| { |
| return (')' == c) || (']' == c) || ('}' == c); |
| } |
| |
| inline bool is_bracket(const char_t c) |
| { |
| return is_left_bracket(c) || is_right_bracket(c); |
| } |
| |
| inline bool is_sign(const char_t c) |
| { |
| return ('+' == c) || ('-' == c); |
| } |
| |
| inline bool is_invalid(const char_t c) |
| { |
| return !is_whitespace (c) && |
| !is_operator_char(c) && |
| !is_letter (c) && |
| !is_digit (c) && |
| ('.' != c) && |
| ('_' != c) && |
| ('$' != c) && |
| ('~' != c) && |
| ('\'' != c); |
| } |
| |
| inline bool imatch(const char_t c1, const char_t c2) |
| { |
| return std::tolower(c1) == std::tolower(c2); |
| } |
| |
| inline bool imatch(const std::string& s1, const std::string& s2) |
| { |
| if (s1.size() == s2.size()) |
| { |
| for (std::size_t i = 0; i < s1.size(); ++i) |
| { |
| if (std::tolower(s1[i]) != std::tolower(s2[i])) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline bool is_valid_sf_symbol(const std::string& symbol) |
| { |
| // Special function: $f12 or $F34 |
| return (4 == symbol.size()) && |
| ('$' == symbol[0]) && |
| imatch('f',symbol[1]) && |
| is_digit(symbol[2]) && |
| is_digit(symbol[3]); |
| } |
| |
| inline const char& front(const std::string& s) |
| { |
| return s[0]; |
| } |
| |
| inline const char& back(const std::string& s) |
| { |
| return s[s.size() - 1]; |
| } |
| |
| inline std::string to_str(int i) |
| { |
| if (0 == i) |
| return std::string("0"); |
| |
| std::string result; |
| |
| if (i < 0) |
| { |
| for ( ; i; i /= 10) |
| { |
| result += '0' + char(-(i % 10)); |
| } |
| |
| result += '-'; |
| } |
| else |
| { |
| for ( ; i; i /= 10) |
| { |
| result += '0' + char(i % 10); |
| } |
| } |
| |
| std::reverse(result.begin(), result.end()); |
| |
| return result; |
| } |
| |
| inline bool is_hex_digit(const std::string::value_type digit) |
| { |
| return (('0' <= digit) && (digit <= '9')) || |
| (('A' <= digit) && (digit <= 'F')) || |
| (('a' <= digit) && (digit <= 'f')) ; |
| } |
| |
| inline uchar_t hex_to_bin(uchar_t h) |
| { |
| if (('0' <= h) && (h <= '9')) |
| return (h - '0'); |
| else |
| return static_cast<unsigned char>(std::toupper(h) - 'A'); |
| } |
| |
| template <typename Iterator> |
| inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result) |
| { |
| if ( |
| (end != (itr )) && |
| (end != (itr + 1)) && |
| (end != (itr + 2)) && |
| (end != (itr + 3)) && |
| ('0' == *(itr )) && |
| ( |
| ('x' == *(itr + 1)) || |
| ('X' == *(itr + 1)) |
| ) && |
| (is_hex_digit(*(itr + 2))) && |
| (is_hex_digit(*(itr + 3))) |
| ) |
| { |
| result = hex_to_bin(*(itr + 2)) << 4 | hex_to_bin(*(itr + 3)); |
| itr += 3; |
| } |
| else |
| result = '\0'; |
| } |
| |
| inline void cleanup_escapes(std::string& s) |
| { |
| typedef std::string::iterator str_itr_t; |
| |
| str_itr_t itr1 = s.begin(); |
| str_itr_t itr2 = s.begin(); |
| str_itr_t end = s.end (); |
| |
| std::size_t removal_count = 0; |
| |
| while (end != itr1) |
| { |
| if ('\\' == (*itr1)) |
| { |
| ++removal_count; |
| |
| if (end == ++itr1) |
| break; |
| else if ('\\' != (*itr1)) |
| { |
| switch (*itr1) |
| { |
| case 'n' : (*itr1) = '\n'; break; |
| case 'r' : (*itr1) = '\r'; break; |
| case 't' : (*itr1) = '\t'; break; |
| case '0' : parse_hex(itr1, end, (*itr1)); |
| removal_count += 3; |
| break; |
| } |
| |
| continue; |
| } |
| } |
| |
| if (itr1 != itr2) |
| { |
| (*itr2) = (*itr1); |
| } |
| |
| ++itr1; |
| ++itr2; |
| } |
| |
| s.resize(s.size() - removal_count); |
| } |
| |
| class build_string |
| { |
| public: |
| |
| build_string(const std::size_t& initial_size = 64) |
| { |
| data_.reserve(initial_size); |
| } |
| |
| inline build_string& operator << (const std::string& s) |
| { |
| data_ += s; |
| return (*this); |
| } |
| |
| inline build_string& operator << (const char* s) |
| { |
| data_ += std::string(s); |
| return (*this); |
| } |
| |
| inline operator std::string () const |
| { |
| return data_; |
| } |
| |
| inline std::string as_string() const |
| { |
| return data_; |
| } |
| |
| private: |
| |
| std::string data_; |
| }; |
| |
| struct ilesscompare |
| { |
| inline bool operator()(const std::string& s1, const std::string& s2) const |
| { |
| const std::size_t length = std::min(s1.size(),s2.size()); |
| |
| for (std::size_t i = 0; i < length; ++i) |
| { |
| const char_t c1 = static_cast<char>(std::tolower(s1[i])); |
| const char_t c2 = static_cast<char>(std::tolower(s2[i])); |
| |
| if (c1 > c2) |
| return false; |
| else if (c1 < c2) |
| return true; |
| } |
| |
| return s1.size() < s2.size(); |
| } |
| }; |
| |
| static const std::string reserved_words[] = |
| { |
| "break", "case", "continue", "default", "false", "for", |
| "if", "else", "ilike", "in", "like", "and", "nand", "nor", |
| "not", "null", "or", "repeat", "return", "shl", "shr", |
| "swap", "switch", "true", "until", "var", "while", "xnor", |
| "xor", "&", "|" |
| }; |
| |
| static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); |
| |
| static const std::string reserved_symbols[] = |
| { |
| "abs", "acos", "acosh", "and", "asin", "asinh", "atan", |
| "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", |
| "continue", "cos", "cosh", "cot", "csc", "default", |
| "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", |
| "expm1", "false", "floor", "for", "frac", "grad2deg", |
| "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", |
| "like", "log", "log10", "log2", "logn", "log1p", "mand", |
| "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", |
| "not", "not_equal", "null", "or", "pow", "rad2deg", |
| "repeat", "return", "root", "round", "roundn", "sec", "sgn", |
| "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", |
| "switch", "tan", "tanh", "true", "trunc", "until", "var", |
| "while", "xnor", "xor", "&", "|" |
| }; |
| |
| static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); |
| |
| static const std::string base_function_list[] = |
| { |
| "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", |
| "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", |
| "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", |
| "frac", "hypot", "iclamp", "like", "log", "log10", "log2", |
| "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", |
| "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", |
| "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", |
| "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", |
| "rad2deg", "grad2deg" |
| }; |
| |
| static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); |
| |
| static const std::string logic_ops_list[] = |
| { |
| "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" |
| }; |
| |
| static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); |
| |
| static const std::string cntrl_struct_list[] = |
| { |
| "if", "switch", "for", "while", "repeat" |
| }; |
| |
| static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); |
| |
| static const std::string arithmetic_ops_list[] = |
| { |
| "+", "-", "*", "/", "%", "^" |
| }; |
| |
| static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); |
| |
| static const std::string assignment_ops_list[] = |
| { |
| ":=", "+=", "-=", |
| "*=", "/=", "%=" |
| }; |
| |
| static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); |
| |
| static const std::string inequality_ops_list[] = |
| { |
| "<", "<=", "==", |
| "=", "!=", "<>", |
| ">=", ">" |
| }; |
| |
| static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / 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; |
| } |
| |
| inline bool is_base_function(const std::string& function_name) |
| { |
| for (std::size_t i = 0; i < base_function_list_size; ++i) |
| { |
| if (imatch(function_name,base_function_list[i])) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| inline bool is_control_struct(const std::string& cntrl_strct) |
| { |
| for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) |
| { |
| if (imatch(cntrl_strct,cntrl_struct_list[i])) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| inline bool is_logic_opr(const std::string& lgc_opr) |
| { |
| for (std::size_t i = 0; i < logic_ops_list_size; ++i) |
| { |
| if (imatch(lgc_opr,logic_ops_list[i])) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| struct cs_match |
| { |
| static inline bool cmp(const char_t c0, const char_t c1) |
| { |
| return (c0 == c1); |
| } |
| }; |
| |
| struct cis_match |
| { |
| static inline bool cmp(const char_t c0, const char_t c1) |
| { |
| return (std::tolower(c0) == std::tolower(c1)); |
| } |
| }; |
| |
| template <typename Iterator, typename Compare> |
| inline bool match_impl(const Iterator pattern_begin, |
| const Iterator pattern_end, |
| const Iterator data_begin, |
| const Iterator data_end, |
| const typename std::iterator_traits<Iterator>::value_type& zero_or_more, |
| const typename std::iterator_traits<Iterator>::value_type& zero_or_one) |
| { |
| if (0 == std::distance(data_begin,data_end)) |
| { |
| return false; |
| } |
| |
| Iterator d_itr = data_begin; |
| Iterator p_itr = pattern_begin; |
| Iterator c_itr = data_begin; |
| Iterator m_itr = data_begin; |
| |
| while ((data_end != d_itr) && (zero_or_more != (*p_itr))) |
| { |
| if ((!Compare::cmp((*p_itr),(*d_itr))) && (zero_or_one != (*p_itr))) |
| { |
| return false; |
| } |
| |
| ++p_itr; |
| ++d_itr; |
| } |
| |
| while (data_end != d_itr) |
| { |
| if (zero_or_more == (*p_itr)) |
| { |
| if (pattern_end == (++p_itr)) |
| { |
| return true; |
| } |
| |
| m_itr = p_itr; |
| c_itr = d_itr; |
| ++c_itr; |
| } |
| else if ((Compare::cmp((*p_itr),(*d_itr))) || (zero_or_one == (*p_itr))) |
| { |
| ++p_itr; |
| ++d_itr; |
| } |
| else |
| { |
| p_itr = m_itr; |
| d_itr = c_itr++; |
| } |
| } |
| |
| while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) { ++p_itr; } |
| |
| return (p_itr == pattern_end); |
| } |
| |
| inline bool wc_match(const std::string& wild_card, |
| const std::string& str) |
| { |
| return match_impl<const char*,cs_match>(wild_card.data(), |
| wild_card.data() + wild_card.size(), |
| str.data(), |
| str.data() + str.size(), |
| '*', |
| '?'); |
| } |
| |
| inline bool wc_imatch(const std::string& wild_card, |
| const std::string& str) |
| { |
| return match_impl<const char*,cis_match>(wild_card.data(), |
| wild_card.data() + wild_card.size(), |
| str.data(), |
| str.data() + str.size(), |
| '*', |
| '?'); |
| } |
| |
| inline bool sequence_match(const std::string& pattern, |
| const std::string& str, |
| std::size_t& diff_index, |
| char& diff_value) |
| { |
| if (str.empty()) |
| { |
| return ("Z" == pattern); |
| } |
| else if ('*' == pattern[0]) |
| return false; |
| |
| typedef std::string::const_iterator itr_t; |
| |
| itr_t p_itr = pattern.begin(); |
| itr_t s_itr = str .begin(); |
| |
| itr_t p_end = pattern.end(); |
| itr_t s_end = str .end(); |
| |
| while ((s_end != s_itr) && (p_end != p_itr)) |
| { |
| if ('*' == (*p_itr)) |
| { |
| const char_t target = static_cast<char>(std::toupper(*(p_itr - 1))); |
| |
| if ('*' == target) |
| { |
| diff_index = std::distance(str.begin(),s_itr); |
| diff_value = static_cast<char>(std::toupper(*p_itr)); |
| |
| return false; |
| } |
| else |
| ++p_itr; |
| |
| while (s_itr != s_end) |
| { |
| if (target != std::toupper(*s_itr)) |
| break; |
| else |
| ++s_itr; |
| } |
| |
| continue; |
| } |
| else if ( |
| ('?' != *p_itr) && |
| std::toupper(*p_itr) != std::toupper(*s_itr) |
| ) |
| { |
| diff_index = std::distance(str.begin(),s_itr); |
| diff_value = static_cast<char>(std::toupper(*p_itr)); |
| |
| return false; |
| } |
| |
| ++p_itr; |
| ++s_itr; |
| } |
| |
| return ( |
| (s_end == s_itr) && |
| ( |
| (p_end == p_itr) || |
| ('*' == *p_itr) |
| ) |
| ); |
| } |
| |
| static const double pow10[] = { |
| 1.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 |
| }; |
| |
| static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); |
| |
| namespace numeric |
| { |
| namespace constant |
| { |
| static const double e = 2.71828182845904523536028747135266249775724709369996; |
| static const double pi = 3.14159265358979323846264338327950288419716939937510; |
| static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; |
| static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; |
| static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; |
| static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; |
| static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; |
| static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; |
| static const double log2 = 0.69314718055994530941723212145817656807550013436026; |
| static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; |
| } |
| |
| namespace details |
| { |
| struct unknown_type_tag {}; |
| struct real_type_tag {}; |
| struct complex_type_tag {}; |
| struct int_type_tag {}; |
| |
| template <typename T> |
| struct number_type { typedef unknown_type_tag type; }; |
| |
| #define exprtk_register_real_type_tag(T) \ |
| template<> struct number_type<T> { typedef real_type_tag type; }; \ |
| |
| #define exprtk_register_complex_type_tag(T) \ |
| template<> struct number_type<std::complex<T> > \ |
| { typedef complex_type_tag type; }; \ |
| |
| #define exprtk_register_int_type_tag(T) \ |
| template<> struct number_type<T> { typedef int_type_tag type; }; \ |
| |
| exprtk_register_real_type_tag(double ) |
| exprtk_register_real_type_tag(long double) |
| exprtk_register_real_type_tag(float ) |
| |
| exprtk_register_complex_type_tag(double ) |
| exprtk_register_complex_type_tag(long double) |
| exprtk_register_complex_type_tag(float ) |
| |
| exprtk_register_int_type_tag(short ) |
| exprtk_register_int_type_tag(int ) |
| exprtk_register_int_type_tag(long long int ) |
| exprtk_register_int_type_tag(unsigned short ) |
| exprtk_register_int_type_tag(unsigned int ) |
| exprtk_register_int_type_tag(unsigned long long int) |
| |
| #undef exprtk_register_real_type_tag |
| #undef exprtk_register_int_type_tag |
| |
| template <typename T> |
| struct epsilon_type |
| { |
| static inline T value() |
| { |
| const T epsilon = T(0.0000000001); |
| return epsilon; |
| } |
| }; |
| |
| template <> |
| struct epsilon_type <float> |
| { |
| static inline float value() |
| { |
| const float epsilon = float(0.000001f); |
| return epsilon; |
| } |
| }; |
| |
| template <> |
| struct epsilon_type <long double> |
| { |
| static inline long double value() |
| { |
| const long double epsilon = (long double)(0.000000000001); |
| return epsilon; |
| } |
| }; |
| |
| template <typename T> |
| inline bool is_nan_impl(const T v, real_type_tag) |
| { |
| return std::not_equal_to<T>()(v,v); |
| } |
| |
| template <typename T> |
| inline int to_int32_impl(const T v, real_type_tag) |
| { |
| return static_cast<int>(v); |
| } |
| |
| template <typename T> |
| inline long long int to_int64_impl(const T v, real_type_tag) |
| { |
| return static_cast<long long int>(v); |
| } |
| |
| template <typename T> |
| inline bool is_true_impl(const T v) |
| { |
| return std::not_equal_to<T>()(T(0),v); |
| } |
| |
| template <typename T> |
| inline bool is_false_impl(const T v) |
| { |
| return std::equal_to<T>()(T(0),v); |
| } |
| |
| template <typename T> |
| inline T abs_impl(const T v, real_type_tag) |
| { |
| return ((v < T(0)) ? -v : v); |
| } |
| |
| template <typename T> |
| inline T min_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::min<T>(v0,v1); |
| } |
| |
| template <typename T> |
| inline T max_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::max<T>(v0,v1); |
| } |
| |
| template <typename T> |
| inline T equal_impl(const T v0, const T v1, real_type_tag) |
| { |
| const T epsilon = epsilon_type<T>::value(); |
| return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0); |
| } |
| |
| inline float equal_impl(const float v0, const float v1, real_type_tag) |
| { |
| const float epsilon = epsilon_type<float>::value(); |
| return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f; |
| } |
| |
| template <typename T> |
| inline T equal_impl(const T v0, const T v1, int_type_tag) |
| { |
| return (v0 == v1) ? 1 : 0; |
| } |
| |
| template <typename T> |
| inline T expm1_impl(const T v, real_type_tag) |
| { |
| // return std::expm1<T>(v); |
| if (abs_impl(v,real_type_tag()) < T(0.00001)) |
| return v + (T(0.5) * v * v); |
| else |
| return std::exp(v) - T(1); |
| } |
| |
| template <typename T> |
| inline T expm1_impl(const T v, int_type_tag) |
| { |
| return T(std::exp<double>(v)) - T(1); |
| } |
| |
| template <typename T> |
| inline T nequal_impl(const T v0, const T v1, real_type_tag) |
| { |
| typedef real_type_tag rtg; |
| const T epsilon = epsilon_type<T>::value(); |
| return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); |
| } |
| |
| inline float nequal_impl(const float v0, const float v1, real_type_tag) |
| { |
| typedef real_type_tag rtg; |
| const float epsilon = epsilon_type<float>::value(); |
| return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; |
| } |
| |
| template <typename T> |
| inline T nequal_impl(const T v0, const T v1, int_type_tag) |
| { |
| return (v0 != v1) ? 1 : 0; |
| } |
| |
| template <typename T> |
| inline T modulus_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::fmod(v0,v1); |
| } |
| |
| template <typename T> |
| inline T modulus_impl(const T v0, const T v1, int_type_tag) |
| { |
| return v0 % v1; |
| } |
| |
| template <typename T> |
| inline T pow_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::pow(v0,v1); |
| } |
| |
| template <typename T> |
| inline T pow_impl(const T v0, const T v1, int_type_tag) |
| { |
| return std::pow(static_cast<double>(v0),static_cast<double>(v1)); |
| } |
| |
| template <typename T> |
| inline T logn_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::log(v0) / std::log(v1); |
| } |
| |
| template <typename T> |
| inline T logn_impl(const T v0, const T v1, int_type_tag) |
| { |
| return static_cast<T>(logn_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag())); |
| } |
| |
| template <typename T> |
| inline T log1p_impl(const T v, real_type_tag) |
| { |
| if (v > T(-1)) |
| { |
| if (abs_impl(v,real_type_tag()) > T(0.0001)) |
| { |
| return std::log(T(1) + v); |
| } |
| else |
| return (T(-0.5) * v + T(1)) * v; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| template <typename T> |
| inline T log1p_impl(const T v, int_type_tag) |
| { |
| if (v > T(-1)) |
| { |
| return std::log(T(1) + v); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| template <typename T> |
| inline T root_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::pow(v0,T(1) / v1); |
| } |
| |
| template <typename T> |
| inline T root_impl(const T v0, const T v1, int_type_tag) |
| { |
| return root_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag()); |
| } |
| |
| template <typename T> |
| inline T round_impl(const T v, real_type_tag) |
| { |
| return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); |
| } |
| |
| template <typename T> |
| inline T roundn_impl(const T v0, const T v1, real_type_tag) |
| { |
| const int index = std::max<int>(0, std::min<int>(pow10_size - 1, (int)std::floor(v1))); |
| const T p10 = T(pow10[index]); |
| |
| if (v0 < T(0)) |
| return T(std::ceil ((v0 * p10) - T(0.5)) / p10); |
| else |
| return T(std::floor((v0 * p10) + T(0.5)) / p10); |
| } |
| |
| template <typename T> |
| inline T roundn_impl(const T v0, const T, int_type_tag) |
| { |
| return v0; |
| } |
| |
| template <typename T> |
| inline T hypot_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::sqrt((v0 * v0) + (v1 * v1)); |
| } |
| |
| template <typename T> |
| inline T hypot_impl(const T v0, const T v1, int_type_tag) |
| { |
| return static_cast<T>(std::sqrt(static_cast<double>((v0 * v0) + (v1 * v1)))); |
| } |
| |
| template <typename T> |
| inline T atan2_impl(const T v0, const T v1, real_type_tag) |
| { |
| return std::atan2(v0,v1); |
| } |
| |
| template <typename T> |
| inline T atan2_impl(const T, const T, int_type_tag) |
| { |
| return 0; |
| } |
| |
| template <typename T> |
| inline T shr_impl(const T v0, const T v1, real_type_tag) |
| { |
| return v0 * (T(1) / std::pow(T(2),static_cast<T>(static_cast<int>(v1)))); |
| } |
| |
| template <typename T> |
| inline T shr_impl(const T v0, const T v1, int_type_tag) |
| { |
| return v0 >> v1; |
| } |
| |
| template <typename T> |
| inline T shl_impl(const T v0, const T v1, real_type_tag) |
| { |
| return v0 * std::pow(T(2),static_cast<T>(static_cast<int>(v1))); |
| } |
| |
| template <typename T> |
| inline T shl_impl(const T v0, const T v1, int_type_tag) |
| { |
| return v0 << v1; |
| } |
| |
| template <typename T> |
| inline T sgn_impl(const T v, real_type_tag) |
| { |
| if (v > T(0)) return T(+1); |
| else if (v < T(0)) return T(-1); |
| else return T( 0); |
| } |
| |
| template <typename T> |
| inline T sgn_impl(const T v, int_type_tag) |
| { |
| if (v > T(0)) return T(+1); |
| else if (v < T(0)) return T(-1); |
| else return T( 0); |
| } |
| |
| template <typename T> |
| inline T and_impl(const T v0, const T v1, real_type_tag) |
| { |
| return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); |
| } |
| |
| template <typename T> |
| inline T and_impl(const T v0, const T v1, int_type_tag) |
| { |
| return v0 && v1; |
| } |
| |
| template <typename T> |
| inline T nand_impl(const T v0, const T v1, real_type_tag) |
| { |
| return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); |
| } |
| |
| template <typename T> |
| inline T nand_impl(const T v0, const T v1, int_type_tag) |
| { |
| return !(v0 && v1); |
| } |
| |
| template <typename T> |
| inline T or_impl(const T v0, const T v1, real_type_tag) |
| { |
| return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); |
| } |
| |
| template <typename T> |
| inline T or_impl(const T v0, const T v1, int_type_tag) |
| { |
| return (v0 || v1); |
| } |
| |
| template <typename T> |
| inline T nor_impl(const T v0, const T v1, real_type_tag) |
| { |
| return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); |
| } |
| |
| template <typename T> |
| inline T nor_impl(const T v0, const T v1, int_type_tag) |
| { |
| return !(v0 || v1); |
| } |
| |
| template <typename T> |
| inline T xor_impl(const T v0, const T v1, real_type_tag) |
| { |
| return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); |
| } |
| |
| template <typename T> |
| inline T xor_impl(const T v0, const T v1, int_type_tag) |
| { |
| return v0 ^ v1; |
| } |
| |
| template <typename T> |
| inline T xnor_impl(const T v0, const T v1, real_type_tag) |
| { |
| const bool v0_true = is_true_impl(v0); |
| const bool v1_true = is_true_impl(v1); |
| |
| if ((v0_true && v1_true) || (!v0_true && !v1_true)) |
| return T(1); |
| else |
| return T(0); |
| } |
| |
| template <typename T> |
| inline T xnor_impl(const T v0, const T v1, int_type_tag) |
| { |
| const bool v0_true = is_true_impl(v0); |
| const bool v1_true = is_true_impl(v1); |
| |
| if ((v0_true && v1_true) || (!v0_true && !v1_true)) |
| return T(1); |
| else |
| return T(0); |
| } |
| |
| #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) |
| #define exprtk_define_erf(TT,impl) \ |
| inline TT erf_impl(TT v) { return impl(v); } \ |
| |
| exprtk_define_erf( float,::erff) |
| exprtk_define_erf( double,::erf ) |
| exprtk_define_erf(long double,::erfl) |
| #undef exprtk_define_erf |
| #endif |
| |
| template <typename T> |
| inline T erf_impl(T v, real_type_tag) |
| { |
| #if defined(_MSC_VER) && (_MSC_VER < 1900) |
| // Credits: Abramowitz & Stegun Equations 7.1.25-28 |
| static const T c[] = { |
| T( 1.26551223), T(1.00002368), |
| T( 0.37409196), T(0.09678418), |
| T(-0.18628806), T(0.27886807), |
| T(-1.13520398), T(1.48851587), |
| T(-0.82215223), T(0.17087277) |
| }; |
| |
| const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); |
| |
| T result = T(1) - t * std::exp((-v * v) - |
| c[0] + t * (c[1] + t * |
| (c[2] + t * (c[3] + t * |
| (c[4] + t * (c[5] + t * |
| (c[6] + t * (c[7] + t * |
| (c[8] + t * (c[9])))))))))); |
| |
| return (v >= T(0)) ? result : -result; |
| #else |
| return erf_impl(v); |
| #endif |
| } |
| |
| template <typename T> |
| inline T erf_impl(T v, int_type_tag) |
| { |
| return erf_impl(static_cast<double>(v),real_type_tag()); |
| } |
| |
| #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) |
| #define exprtk_define_erfc(TT,impl) \ |
| inline TT erfc_impl(TT v) { return impl(v); } \ |
| |
| exprtk_define_erfc( float,::erfcf) |
| exprtk_define_erfc( double,::erfc ) |
| exprtk_define_erfc(long double,::erfcl) |
| #undef exprtk_define_erfc |
| #endif |
| |
| template <typename T> |
| inline T erfc_impl(T v, real_type_tag) |
| { |
| #if defined(_MSC_VER) && (_MSC_VER < 1900) |
| return T(1) - erf_impl(v,real_type_tag()); |
| #else |
| return erfc_impl(v); |
| #endif |
| } |
| |
| template <typename T> |
| inline T erfc_impl(T v, int_type_tag) |
| { |
| return erfc_impl(static_cast<double>(v),real_type_tag()); |
| } |
| |
| template <typename T> |
| inline T ncdf_impl(T v, real_type_tag) |
| { |
| T cnd = T(0.5) * (T(1) + erf_impl( |
| abs_impl(v,real_type_tag()) / |
| T(numeric::constant::sqrt2),real_type_tag())); |
| return (v < T(0)) ? (T(1) - cnd) : cnd; |
| } |
| |
| template <typename T> |
| inline T ncdf_impl(T v, int_type_tag) |
| { |
| return ncdf_impl(static_cast<double>(v),real_type_tag()); |
| } |
| |
| template <typename T> |
| inline T sinc_impl(T v, real_type_tag) |
| { |
| if (std::abs(v) >= std::numeric_limits<T>::epsilon()) |
| return(std::sin(v) / v); |
| else |
| return T(1); |
| } |
| |
| template <typename T> |
| inline T sinc_impl(T v, int_type_tag) |
| { |
| return sinc_impl(static_cast<double>(v),real_type_tag()); |
| } |
| |
| template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } |
| template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } |
| template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } |
| template <typename T> inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } |
| template <typename T> inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } |
| template <typename T> inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } |
| template <typename T> inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } |
| template <typename T> inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } |
| template <typename T> inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } |
| template <typename T> inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } |
| template <typename T> inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } |
| template <typename T> inline T log_impl(const T v, real_type_tag) { return std::log (v); } |
| template <typename T> inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } |
| template <typename T> inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } |
| template <typename T> inline T neg_impl(const T v, real_type_tag) { return -v; } |
| template <typename T> inline T pos_impl(const T v, real_type_tag) { return +v; } |
| template <typename T> inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } |
| template <typename T> inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } |
| template <typename T> inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } |
| template <typename T> inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } |
| template <typename T> inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } |
| template <typename T> inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } |
| template <typename T> inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } |
| template <typename T> inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } |
| template <typename T> inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } |
| template <typename T> inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } |
| template <typename T> inline T d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); } |
| template <typename T> inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); } |
| template <typename T> inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to<T>()(T(0),v) ? T(0) : T(1)); } |
| template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); } |
| template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); } |
| |
| template <typename T> inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } |
| template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } |
| template <typename T> inline T log_impl(const T v, int_type_tag) { return std::log (v); } |
| template <typename T> inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } |
| template <typename T> inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } |
| template <typename T> inline T neg_impl(const T v, int_type_tag) { return -v; } |
| template <typename T> inline T pos_impl(const T v, int_type_tag) { return +v; } |
| template <typename T> inline T ceil_impl(const T v, int_type_tag) { return v; } |
| template <typename T> inline T floor_impl(const T v, int_type_tag) { return v; } |
| template <typename T> inline T round_impl(const T v, int_type_tag) { return v; } |
| template <typename T> inline T notl_impl(const T v, int_type_tag) { return !v; } |
| template <typename T> inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } |
| template <typename T> inline T frac_impl(const T , int_type_tag) { return T(0); } |
| template <typename T> inline T trunc_impl(const T v, int_type_tag) { return v; } |
| template <typename T> inline T acos_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T asin_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T atan_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T cos_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T sin_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T tan_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T cot_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T sec_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| template <typename T> inline T csc_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } |
| |
| template <typename T> |
| inline bool is_integer_impl(const T& v, real_type_tag) |
| { |
| return std::equal_to<T>()(T(0),std::fmod(v,T(1))); |
| } |
| |
| template <typename T> |
| inline bool is_integer_impl(const T&, int_type_tag) |
| { |
| return true; |
| } |
| } |
| |
| template <typename Type> |
| struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; |
| |
| template<> struct numeric_info<int> { enum { length = 10, size = 16, bound_length = 9}; }; |
| template<> struct numeric_info<float> { enum { min_exp = -38, max_exp = +38}; }; |
| template<> struct numeric_info<double> { enum { min_exp = -308, max_exp = +308}; }; |
| template<> struct numeric_info<long double> { enum { min_exp = -308, max_exp = +308}; }; |
| |
| template <typename T> |
| inline int to_int32(const T v) |
| { |
| typename details::number_type<T>::type num_type; |
| return to_int32_impl(v,num_type); |
| } |
| |
| template <typename T> |
| inline long long int to_int64(const T v) |
| { |
| typename details::number_type<T>::type num_type; |
| return to_int64_impl(v,num_type); |
| } |
| |
| template <typename T> |
| inline bool is_nan(const T v) |
| { |
| typename details::number_type<T>::type num_type; |
| return is_nan_impl(v,num_type); |
| } |
| |
| template <typename T> |
| inline T min(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return min_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T max(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return max_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T equal(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return equal_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T nequal(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return nequal_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T modulus(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return modulus_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T pow(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return pow_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T logn(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return logn_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T root(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return root_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T roundn(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return roundn_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T hypot(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return hypot_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T atan2(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return atan2_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T shr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return shr_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T shl(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return shl_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T and_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return and_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T nand_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return nand_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T or_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return or_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T nor_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return nor_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T xor_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return xor_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline T xnor_opr(const T v0, const T v1) |
| { |
| typename details::number_type<T>::type num_type; |
| return xnor_impl(v0,v1,num_type); |
| } |
| |
| template <typename T> |
| inline bool is_integer(const T v) |
| { |
| typename details::number_type<T>::type num_type; |
| return is_integer_impl(v,num_type); |
| } |
| |
| template <typename T, unsigned int N> |
| struct fast_exp |
| { |
| static inline T result(T v) |
| { |
| unsigned int k = N; |
| T l = T(1); |
| |
| while (k) |
| { |
| if (k & 1) |
| { |
| l *= v; |
| --k; |
| } |
| |
| v *= v; |
| k >>= 1; |
| } |
| |
| return l; |
| } |
| }; |
| |
| template <typename T> struct fast_exp<T,10> { static inline T result(T v) { T v_5 = fast_exp<T,5>::result(v); return v_5 * v_5; } }; |
| template <typename T> struct fast_exp<T, 9> { static inline T result(T v) { return fast_exp<T,8>::result(v) * v; } }; |
| template <typename T> struct fast_exp<T, 8> { static inline T result(T v) { T v_4 = fast_exp<T,4>::result(v); return v_4 * v_4; } }; |
| template <typename T> struct fast_exp<T, 7> { static inline T result(T v) { return fast_exp<T,6>::result(v) * v; } }; |
| template <typename T> struct fast_exp<T, 6> { static inline T result(T v) { T v_3 = fast_exp<T,3>::result(v); return v_3 * v_3; } }; |
| template <typename T> struct fast_exp<T, 5> { static inline T result(T v) { return fast_exp<T,4>::result(v) * v; } }; |
| template <typename T> struct fast_exp<T, 4> { static inline T result(T v) { T v_2 = v * v; return v_2 * v_2; } }; |
| template <typename T> struct fast_exp<T, 3> { static inline T result(T v) { return v * v * v; } }; |
| template <typename T> struct fast_exp<T, 2> { static inline T result(T v) { return v * v; } }; |
| template <typename T> struct fast_exp<T, 1> { static inline T result(T v) { return v; } }; |
| template <typename T> struct fast_exp<T, 0> { static inline T result(T ) { return T(1); } }; |
| |
| #define exprtk_define_unary_function(FunctionName) \ |
| template <typename T> \ |
| inline T FunctionName (const T v) \ |
| { \ |
| typename details::number_type<T>::type num_type; \ |
| return FunctionName##_impl(v,num_type); \ |
| } \ |
| |
| exprtk_define_unary_function(abs ) |
| exprtk_define_unary_function(acos ) |
| exprtk_define_unary_function(acosh) |
| exprtk_define_unary_function(asin ) |
| exprtk_define_unary_function(asinh) |
| exprtk_define_unary_function(atan ) |
| exprtk_define_unary_function(atanh) |
| exprtk_define_unary_function(ceil ) |
| exprtk_define_unary_function(cos ) |
| exprtk_define_unary_function(cosh ) |
| exprtk_define_unary_function(exp ) |
| exprtk_define_unary_function(expm1) |
| exprtk_define_unary_function(floor) |
| exprtk_define_unary_function(log ) |
| exprtk_define_unary_function(log10) |
| exprtk_define_unary_function(log2 ) |
| exprtk_define_unary_function(log1p) |
| exprtk_define_unary_function(neg ) |
| exprtk_define_unary_function(pos ) |
| exprtk_define_unary_function(round) |
| exprtk_define_unary_function(sin ) |
| exprtk_define_unary_function(sinc ) |
| exprtk_define_unary_function(sinh ) |
| exprtk_define_unary_function(sqrt ) |
| exprtk_define_unary_function(tan ) |
| exprtk_define_unary_function(tanh ) |
| exprtk_define_unary_function(cot ) |
| exprtk_define_unary_function(sec ) |
| exprtk_define_unary_function(csc ) |
| exprtk_define_unary_function(r2d ) |
| exprtk_define_unary_function(d2r ) |
| exprtk_define_unary_function(d2g ) |
| exprtk_define_unary_function(g2d ) |
| exprtk_define_unary_function(notl ) |
| exprtk_define_unary_function(sgn ) |
| exprtk_define_unary_function(erf ) |
| exprtk_define_unary_function(erfc ) |
| exprtk_define_unary_function(ncdf ) |
| exprtk_define_unary_function(frac ) |
| exprtk_define_unary_function(trunc) |
| #undef exprtk_define_unary_function |
| } |
| |
| template <typename T> |
| inline T compute_pow10(T d, const int 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+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, |
| 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, |
| 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 int fract10_size = static_cast<int>(sizeof(fract10) / sizeof(double)); |
| |
| const int e = std::abs(exponent); |
| |
| if (exponent >= std::numeric_limits<T>::min_exponent10) |
| { |
| if (e < fract10_size) |
| { |
| if (exponent > 0) |
| return T(d * fract10[e]); |
| else |
| return T(d / fract10[e]); |
| } |
| else |
| return T(d * std::pow(10.0, 10.0 * exponent)); |
| } |
| else |
| { |
| d /= T(fract10[ -std::numeric_limits<T>::min_exponent10]); |
| return T(d / fract10[-exponent + std::numeric_limits<T>::min_exponent10]); |
| } |
| } |
| |
| template <typename Iterator, typename T> |
| inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result) |
| { |
| if (itr == end) |
| return false; |
| |
| bool negative = ('-' == (*itr)); |
| |
| if (negative || ('+' == (*itr))) |
| { |
| if (end == ++itr) |
| return false; |
| } |
| |
| while ((end != itr) && ('0' == (*itr))) ++itr; |
| |
| bool return_result = true; |
| unsigned int digit = 0; |
| const std::size_t length = std::distance(itr,end); |
| |
| if (length <= 4) |
| { |
| switch (length) |
| { |
| #ifdef exprtk_use_lut |
| |
| #define exprtk_process_digit \ |
| if ((digit = details::digit_table[(int)*itr++]) < 10) result = result * 10 + (digit); else { return_result = false; break; } |
| |
| #else |
| #define exprtk_process_digit \ |
| if ((digit = (*itr++ - '0')) < 10) result = result * 10 + (digit); else { return_result = false; break; } |
| |
| #endif |
| |
| case 4 : exprtk_process_digit |
| case 3 : exprtk_process_digit |
| case 2 : exprtk_process_digit |
| case 1 : if ((digit = (*itr - '0'))>= 10) { digit = 0; return_result = false; } |
| |
| #undef exprtk_process_digit |
| } |
| } |
| else |
| return_result = false; |
| |
| if (length && return_result) |
| { |
| result = result * 10 + static_cast<T>(digit); |
| ++itr; |
| } |
| |
| result = negative ? -result : result; |
| return return_result; |
| } |
| |
| template <typename Iterator, typename T> |
| static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) |
| { |
| typedef typename std::iterator_traits<Iterator>::value_type type; |
| |
| static const std::size_t nan_length = 3; |
| |
| if (std::distance(itr,end) != static_cast<int>(nan_length)) |
| return false; |
| |
| if (static_cast<type>('n') == (*itr)) |
| { |
| if ( |
| (static_cast<type>('a') != *(itr + 1)) || |
| (static_cast<type>('n') != *(itr + 2)) |
| ) |
| { |
| return false; |
| } |
| } |
| else if ( |
| (static_cast<type>('A') != *(itr + 1)) || |
| (static_cast<type>('N') != *(itr + 2)) |
| ) |
| { |
| return false; |
| } |
| |
| t = std::numeric_limits<T>::quiet_NaN(); |
| |
| return true; |
| } |
| |
| template <typename Iterator, typename T> |
| static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) |
| { |
| static const char_t inf_uc[] = "INFINITY"; |
| static const char_t 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<char>(*itr)) |
| { |
| ++itr; |
| ++inf_itr; |
| continue; |
| } |
| else |
| return false; |
| } |
| |
| if (negative) |
| t = -std::numeric_limits<T>::infinity(); |
| else |
| t = std::numeric_limits<T>::infinity(); |
| |
| return true; |
| } |
| |
| template <typename Iterator, typename T> |
| inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) |
| { |
| if (end == itr_external) return false; |
| |
| Iterator itr = itr_external; |
| |
| T d = T(0); |
| |
| bool negative = ('-' == (*itr)); |
| |
| if (negative || '+' == (*itr)) |
| { |
| if (end == ++itr) |
| return false; |
| } |
| |
| bool instate = false; |
| |
| #define parse_digit_1(d) \ |
| if ((digit = (*itr - '0')) < 10) \ |
| { d = d * T(10) + digit; } \ |
| else \ |
| { break; } \ |
| if (end == ++itr) break; \ |
| |
| #define parse_digit_2(d) \ |
| if ((digit = (*itr - '0')) < 10) \ |
| { d = d * T(10) + digit; } \ |
| else { break; } \ |
| ++itr; \ |
| |
| if ('.' != (*itr)) |
| { |
| const Iterator curr = itr; |
| while ((end != itr) && ('0' == (*itr))) ++itr; |
| unsigned int digit; |
| |
| while (end != itr) |
| { |
| // Note: For 'physical' superscalar architectures it |
| // is advised that the following loop be: 4xPD1 and 1xPD2 |
| #ifdef exprtk_enable_superscalar |
| parse_digit_1(d) |
| parse_digit_1(d) |
| #endif |
| parse_digit_1(d) |
| parse_digit_1(d) |
| parse_digit_2(d) |
| } |
| |
| if (curr != itr) instate = true; |
| } |
| |
| int exponent = 0; |
| |
| if (end != itr) |
| { |
| if ('.' == (*itr)) |
| { |
| const Iterator curr = ++itr; |
| unsigned int digit; |
| T tmp_d = T(0); |
| |
| while (end != itr) |
| { |
| #ifdef exprtk_enable_superscalar |
| parse_digit_1(tmp_d) |
| parse_digit_1(tmp_d) |
| parse_digit_1(tmp_d) |
| #endif |
| parse_digit_1(tmp_d) |
| parse_digit_1(tmp_d) |
| parse_digit_2(tmp_d) |
| } |
| |
| if (curr != itr) |
| { |
| instate = true; |
| d += compute_pow10(tmp_d,static_cast<int>(-std::distance(curr,itr))); |
| } |
| |
| #undef parse_digit_1 |
| #undef parse_digit_2 |
| } |
| |
| if (end != itr) |
| { |
| typename std::iterator_traits<Iterator>::value_type c = (*itr); |
| |
| if (('e' == c) || ('E' == c)) |
| { |
| int exp = 0; |
| |
| if (!details::string_to_type_converter_impl_ref(++itr,end,exp)) |
| { |
| if (end == itr) |
| return false; |
| else |
| c = (*itr); |
| } |
| |
| exponent += exp; |
| } |
| |
| if (end != itr) |
| { |
| if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) |
| ++itr; |
| else if ('#' == c) |
| { |
| if (end == ++itr) |
| return false; |
| else 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; |
| } |
| else |
| return false; |
| } |
| else 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; |
| } |
| else |
| return false; |
| } |
| } |
| } |
| |
| if ((end != itr) || (!instate)) |
| return false; |
| else if (exponent) |
| d = compute_pow10(d,exponent); |
| |
| t = static_cast<T>((negative) ? -d : d); |
| return true; |
| } |
| |
| template <typename T> |
| inline bool string_to_real(const std::string& s, T& t) |
| { |
| const char* begin = s.data(); |
| const char* end = s.data() + s.size(); |
| typename numeric::details::number_type<T>::type num_type; |
| return string_to_real(begin,end,t,num_type); |
| } |
| |
| template <typename T> |
| struct functor_t |
| { |
| /* |
| Note: The following definitions for Type, may require tweaking |
| based on the compiler and target architecture. The benchmark |
| should provide enough information to make the right choice. |
| */ |
| //typedef T Type; |
| //typedef const T Type; |
| typedef const T& Type; |
| typedef T& RefType; |
| typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); |
| typedef T (*tfunc_t)(Type t0, Type t1, Type t2); |
| typedef T (*bfunc_t)(Type t0, Type t1); |
| typedef T (*ufunc_t)(Type t0); |
| }; |
| |
| } // namespace details |
| |
| namespace lexer |
| { |
| struct token |
| { |
| enum token_type |
| { |
| e_none = 0, e_error = 1, e_err_symbol = 2, |
| e_err_number = 3, e_err_string = 4, e_err_sfunc = 5, |
| e_eof = 6, e_number = 7, e_symbol = 8, |
| e_string = 9, e_assign = 10, e_addass = 11, |
| e_subass = 12, e_mulass = 13, e_divass = 14, |
| e_modass = 15, e_shr = 16, e_shl = 17, |
| e_lte = 18, e_ne = 19, e_gte = 20, |
| e_swap = 21, e_lt = '<', e_gt = '>', |
| e_eq = '=', e_rbracket = ')', e_lbracket = '(', |
| e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', |
| e_lcrlbracket = '{', e_comma = ',', e_add = '+', |
| e_sub = '-', e_div = '/', e_mul = '*', |
| e_mod = '%', e_pow = '^', e_colon = ':', |
| e_ternary = '?' |
| }; |
| |
| token() |
| : type(e_none), |
| value(""), |
| position(std::numeric_limits<std::size_t>::max()) |
| {} |
| |
| void clear() |
| { |
| type = e_none; |
| value = ""; |
| position = std::numeric_limits<std::size_t>::max(); |
| } |
| |
| template <typename Iterator> |
| inline token& set_operator(const token_type tt, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) |
| { |
| type = tt; |
| value.assign(begin,end); |
| if (base_begin) |
| position = std::distance(base_begin,begin); |
| return *this; |
| } |
| |
| template <typename Iterator> |
| inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) |
| { |
| type = e_symbol; |
| value.assign(begin,end); |
| if (base_begin) |
| position = std::distance(base_begin,begin); |
| return *this; |
| } |
| |
| template <typename Iterator> |
| inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) |
| { |
| type = e_number; |
| value.assign(begin,end); |
| if (base_begin) |
| position = std::distance(base_begin,begin); |
| return *this; |
| } |
| |
| template <typename Iterator> |
| inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) |
| { |
| type = e_string; |
| value.assign(begin,end); |
| if (base_begin) |
| position = std::distance(base_begin,begin); |
| return *this; |
| } |
| |
| inline token& set_string(const std::string& s, const std::size_t p) |
| { |
| type = e_string; |
| value = s; |
| position = p; |
| return *this; |
| } |
| |
| template <typename Iterator> |
| inline token& set_error(const token_type et, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) |
| { |
| if ( |
| (e_error == et) || |
| (e_err_symbol == et) || |
| (e_err_number == et) || |
| (e_err_string == et) || |
| (e_err_sfunc == et) |
| ) |
| { |
| type = et; |
| } |
| else |
| type = e_error; |
| |
| value.assign(begin,end); |
| |
| if (base_begin) |
| position = std::distance(base_begin,begin); |
| |
| return *this; |
| } |
| |
| static inline std::string to_str(token_type t) |
| { |
| switch (t) |
| { |
| case e_none : return "NONE"; |
| case e_error : return "ERROR"; |
| case e_err_symbol : return "ERROR_SYMBOL"; |
| case e_err_number : return "ERROR_NUMBER"; |
| case e_err_string : return "ERROR_STRING"; |
| case e_eof : return "EOF"; |
| case e_number : return "NUMBER"; |
| case e_symbol : return "SYMBOL"; |
| case e_string : return "STRING"; |
| case e_assign : return ":="; |
| case e_addass : return "+="; |
| case e_subass : return "-="; |
| case e_mulass : return "*="; |
| case e_divass : return "/="; |
| case e_modass : return "%="; |
| case e_shr : return ">>"; |
| case e_shl : return "<<"; |
| case e_lte : return "<="; |
| case e_ne : return "!="; |
| case e_gte : return ">="; |
| case e_lt : return "<"; |
| case e_gt : return ">"; |
| case e_eq : return "="; |
| case e_rbracket : return ")"; |
| case e_lbracket : return "("; |
| case e_rsqrbracket : return "]"; |
| case e_lsqrbracket : return "["; |
| case e_rcrlbracket : return "}"; |
| case e_lcrlbracket : return "{"; |
| case e_comma : return ","; |
| case e_add : return "+"; |
| case e_sub : return "-"; |
| case e_div : return "/"; |
| case e_mul : return "*"; |
| case e_mod : return "%"; |
| case e_pow : return "^"; |
| case e_colon : return ":"; |
| case e_ternary : return "?"; |
| case e_swap : return "<=>"; |
| default : return "UNKNOWN"; |
| } |
| } |
| |
| inline bool is_error() const |
| { |
| return ( |
| (e_error == type) || |
| (e_err_symbol == type) || |
| (e_err_number == type) || |
| (e_err_string == type) || |
| (e_err_sfunc == type) |
| ); |
| } |
| |
| token_type type; |
| std::string value; |
| std::size_t position; |
| }; |
| |
| class generator |
| { |
| public: |
| |
| typedef token token_t; |
| typedef std::vector<token_t> token_list_t; |
| typedef std::vector<token_t>::iterator token_list_itr_t; |
| typedef details::char_t char_t; |
| |
| generator() |
| : base_itr_(0), |
| s_itr_ (0), |
| s_end_ (0) |
| { |
| clear(); |
| } |
| |
| inline void clear() |
| { |
| base_itr_ = 0; |
| s_itr_ = 0; |
| s_end_ = 0; |
| token_list_.clear(); |
| token_itr_ = token_list_.end(); |
| store_token_itr_ = token_list_.end(); |
| } |
| |
| inline bool process(const std::string& str) |
| { |
| base_itr_ = str.data(); |
| s_itr_ = str.data(); |
| s_end_ = str.data() + str.size(); |
| |
| eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); |
| token_list_.clear(); |
| |
| while (!is_end(s_itr_)) |
| { |
| scan_token(); |
| |
| if (token_list_.empty()) |
| return true; |
| else if (token_list_.back().is_error()) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| inline bool empty() const |
| { |
| return token_list_.empty(); |
| } |
| |
| inline std::size_t size() const |
| { |
| return token_list_.size(); |
| } |
| |
| inline void begin() |
| { |
| token_itr_ = token_list_.begin(); |
| store_token_itr_ = token_list_.begin(); |
| } |
| |
| inline void store() |
| { |
| store_token_itr_ = token_itr_; |
| } |
| |
| inline void restore() |
| { |
| token_itr_ = store_token_itr_; |
| } |
| |
| inline token_t& next_token() |
| { |
| if (token_list_.end() != token_itr_) |
| { |
| return *token_itr_++; |
| } |
| else |
| return eof_token_; |
| } |
| |
| inline token_t& peek_next_token() |
| { |
| if (token_list_.end() != token_itr_) |
| { |
| return *token_itr_; |
| } |
| else |
| return eof_token_; |
| } |
| |
| inline token_t& operator[](const std::size_t& index) |
| { |
| if (index < token_list_.size()) |
| return token_list_[index]; |
| else |
| return eof_token_; |
| } |
| |
| inline token_t operator[](const std::size_t& index) const |
| { |
| if (index < token_list_.size()) |
| return token_list_[index]; |
| else |
| return eof_token_; |
| } |
| |
| inline bool finished() const |
| { |
| return (token_list_.end() == token_itr_); |
| } |
| |
| inline void insert_front(token_t::token_type tk_type) |
| { |
| if ( |
| !token_list_.empty() && |
| (token_list_.end() != token_itr_) |
| ) |
| { |
| token_t t = *token_itr_; |
| |
| t.type = tk_type; |
| token_itr_ = token_list_.insert(token_itr_,t); |
| } |
| } |
| |
| inline std::string substr(const std::size_t& begin, const std::size_t& end) |
| { |
| const char* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; |
| const char* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; |
| |
| return std::string(begin_itr,end_itr); |
| } |
| |
| inline std::string remaining() const |
| { |
| if (finished()) |
| return ""; |
| else if (token_list_.begin() != token_itr_) |
| return std::string(base_itr_ + (token_itr_ - 1)->position,s_end_); |
| else |
| return std::string(base_itr_ + token_itr_->position,s_end_); |
| } |
| |
| private: |
| |
| inline bool is_end(const char* itr) |
| { |
| return (s_end_ == itr); |
| } |
| |
| inline void skip_whitespace() |
| { |
| while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) |
| { |
| ++s_itr_; |
| } |
| } |
| |
| inline void skip_comments() |
| { |
| #ifndef exprtk_disable_comments |
| // The following comment styles are supported: |
| // 1. // .... \n |
| // 2. # .... \n |
| // 3. /* .... */ |
| struct test |
| { |
| static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) |
| { |
| mode = 0; |
| if ('#' == c0) { mode = 1; incr = 1; } |
| else if ('/' == c0) |
| { |
| if ('/' == c1) { mode = 1; incr = 2; } |
| else if ('*' == c1) { mode = 2; incr = 2; } |
| } |
| return (0 != mode); |
| } |
| |
| static inline bool comment_end(const char_t c0, const char_t c1, const int mode) |
| { |
| return ( |
| ((1 == mode) && ('\n' == c0)) || |
| ((2 == mode) && ( '*' == c0) && ('/' == c1)) |
| ); |
| } |
| }; |
| |
| int mode = 0; |
| int increment = 0; |
| |
| if (is_end(s_itr_) || is_end((s_itr_ + 1))) |
| return; |
| else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment)) |
| return; |
| |
| s_itr_ += increment; |
| |
| while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode)) |
| { |
| ++s_itr_; |
| } |
| |
| if (!is_end(s_itr_)) |
| { |
| s_itr_ += mode; |
| skip_whitespace(); |
| skip_comments(); |
| } |
| #endif |
| } |
| |
| inline void scan_token() |
| { |
| skip_whitespace(); |
| |
| skip_comments(); |
| |
| if (is_end(s_itr_)) |
| { |
| return; |
| } |
| else if (details::is_operator_char(*s_itr_)) |
| { |
| scan_operator(); |
| return; |
| } |
| else if (details::is_letter(*s_itr_)) |
| { |
| scan_symbol(); |
| return; |
| } |
| else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) |
| { |
| scan_number(); |
| return; |
| } |
| else if ('$' == (*s_itr_)) |
| { |
| scan_special_function(); |
| return; |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if ('\'' == (*s_itr_)) |
| { |
| scan_string(); |
| return; |
| } |
| #endif |
| else if ('~' == (*s_itr_)) |
| { |
| token_t t; |
| t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); |
| token_list_.push_back(t); |
| ++s_itr_; |
| return; |
| } |
| else |
| { |
| token_t t; |
| t.set_error(token::e_error,s_itr_,s_itr_ + 2,base_itr_); |
| token_list_.push_back(t); |
| ++s_itr_; |
| } |
| } |
| |
| inline void scan_operator() |
| { |
| token_t t; |
| |
| const char_t c0 = s_itr_[0]; |
| |
| if (!is_end(s_itr_ + 1)) |
| { |
| const char_t c1 = s_itr_[1]; |
| |
| if (!is_end(s_itr_ + 2)) |
| { |
| const char_t c2 = s_itr_[2]; |
| |
| if ((c0 == '<') && (c1 == '=') && (c2 == '>')) |
| { |
| t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_); |
| token_list_.push_back(t); |
| s_itr_ += 3; |
| return; |
| } |
| } |
| |
| token_t::token_type ttype = token_t::e_none; |
| |
| if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; |
| else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; |
| else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; |
| else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; |
| else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; |
| else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; |
| else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; |
| else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; |
| else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; |
| else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; |
| else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; |
| else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; |
| else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; |
| |
| if (token_t::e_none != ttype) |
| { |
| t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_); |
| token_list_.push_back(t); |
| s_itr_ += 2; |
| return; |
| } |
| } |
| |
| if ('<' == c0) |
| t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); |
| else if ('>' == c0) |
| t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); |
| else if (';' == c0) |
| t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); |
| else if ('&' == c0) |
| t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); |
| else if ('|' == c0) |
| t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); |
| else |
| t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_); |
| |
| token_list_.push_back(t); |
| ++s_itr_; |
| } |
| |
| inline void scan_symbol() |
| { |
| const char* initial_itr = s_itr_; |
| |
| while (!is_end(s_itr_)) |
| { |
| if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) |
| { |
| if ('.' != (*s_itr_)) |
| break; |
| /* |
| Permit symbols that contain a 'dot' |
| Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 |
| Disallowed: .abc, abc.<white-space>, abc.<eof>, abc.<operator +,-,*,/...> |
| */ |
| if ( |
| (s_itr_ != initial_itr) && |
| !is_end(s_itr_ + 1) && |
| details::is_letter_or_digit(*s_itr_ + 1) && |
| ('_' != (*s_itr_ + 1)) |
| ) |
| break; |
| } |
| |
| ++s_itr_; |
| } |
| |
| token_t t; |
| t.set_symbol(initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| } |
| |
| inline void scan_number() |
| { |
| /* |
| Attempt to match a valid numeric value in one of the following formats: |
| 01. 123456 |
| 02. 123.456 |
| 03. 123.456e3 |
| 04. 123.456E3 |
| 05. 123.456e+3 |
| 06. 123.456E+3 |
| 07. 123.456e-3 |
| 08. 123.456E-3 |
| 09. .1234 |
| 10. .1234e3 |
| 11. .1234E+3 |
| 12. .1234e+3 |
| 13. .1234E-3 |
| 14. .1234e-3 |
| */ |
| const char* initial_itr = s_itr_; |
| bool dot_found = false; |
| bool e_found = false; |
| bool post_e_sign_found = false; |
| bool post_e_digit_found = false; |
| token_t t; |
| |
| while (!is_end(s_itr_)) |
| { |
| if ('.' == (*s_itr_)) |
| { |
| if (dot_found) |
| { |
| t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| return; |
| } |
| |
| dot_found = true; |
| ++s_itr_; |
| |
| continue; |
| } |
| else if (details::imatch('e',(*s_itr_))) |
| { |
| const char& c = *(s_itr_ + 1); |
| |
| if (is_end(s_itr_ + 1)) |
| { |
| t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| else if ( |
| ('+' != c) && |
| ('-' != c) && |
| !details::is_digit(c) |
| ) |
| { |
| t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| e_found = true; |
| ++s_itr_; |
| |
| continue; |
| } |
| else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) |
| { |
| if (post_e_sign_found) |
| { |
| t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| post_e_sign_found = true; |
| ++s_itr_; |
| |
| continue; |
| } |
| else if (e_found && details::is_digit(*s_itr_)) |
| { |
| post_e_digit_found = true; |
| ++s_itr_; |
| |
| continue; |
| } |
| else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) |
| break; |
| else |
| ++s_itr_; |
| } |
| |
| t.set_numeric(initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| inline void scan_special_function() |
| { |
| const char* initial_itr = s_itr_; |
| token_t t; |
| |
| // $fdd(x,x,x) = at least 11 chars |
| if (std::distance(s_itr_,s_end_) < 11) |
| { |
| t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| if ( |
| !(('$' == *s_itr_) && |
| (details::imatch ('f',*(s_itr_ + 1))) && |
| (details::is_digit(*(s_itr_ + 2))) && |
| (details::is_digit(*(s_itr_ + 3)))) |
| ) |
| { |
| t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| s_itr_ += 4; // $fdd = 4chars |
| |
| t.set_symbol(initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline void scan_string() |
| { |
| const char* initial_itr = s_itr_ + 1; |
| token_t t; |
| |
| if (std::distance(s_itr_,s_end_) < 2) |
| { |
| t.set_error(token::e_err_string,s_itr_,s_end_,base_itr_); |
| token_list_.push_back(t); |
| return; |
| } |
| |
| ++s_itr_; |
| |
| bool escaped_found = false; |
| bool escaped = false; |
| |
| while (!is_end(s_itr_)) |
| { |
| if (!escaped && ('\\' == *s_itr_)) |
| { |
| escaped_found = true; |
| escaped = true; |
| ++s_itr_; |
| |
| continue; |
| } |
| else if (!escaped) |
| { |
| if ('\'' == *s_itr_) |
| break; |
| } |
| else if (escaped) |
| { |
| if (!is_end(s_itr_) && ('0' == *(s_itr_))) |
| { |
| /* |
| Note: The following 'awkward' conditional is |
| due to various broken msvc compilers. |
| */ |
| #if _MSC_VER == 1600 |
| const bool within_range = !is_end(s_itr_ + 2) && |
| !is_end(s_itr_ + 3) ; |
| #else |
| const bool within_range = !is_end(s_itr_ + 1) && |
| !is_end(s_itr_ + 2) && |
| !is_end(s_itr_ + 3) ; |
| #endif |
| |
| const bool x_seperator = ('x' == *(s_itr_ + 1)) || |
| ('X' == *(s_itr_ + 1)) ; |
| |
| const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && |
| details::is_hex_digit(*(s_itr_ + 3)) ; |
| |
| if (!within_range || !x_seperator || !both_digits) |
| { |
| t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| else |
| s_itr_ += 3; |
| } |
| |
| escaped = false; |
| } |
| |
| ++s_itr_; |
| } |
| |
| if (is_end(s_itr_)) |
| { |
| t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); |
| token_list_.push_back(t); |
| |
| return; |
| } |
| |
| if (!escaped_found) |
| t.set_string(initial_itr,s_itr_,base_itr_); |
| else |
| { |
| std::string parsed_string(initial_itr,s_itr_); |
| details::cleanup_escapes(parsed_string); |
| t.set_string(parsed_string, std::distance(base_itr_,initial_itr)); |
| } |
| |
| token_list_.push_back(t); |
| ++s_itr_; |
| |
| return; |
| } |
| #endif |
| |
| private: |
| |
| token_list_t token_list_; |
| token_list_itr_t token_itr_; |
| token_list_itr_t store_token_itr_; |
| token_t eof_token_; |
| const char* base_itr_; |
| const char* s_itr_; |
| const char* s_end_; |
| |
| friend class token_scanner; |
| friend class token_modifier; |
| friend class token_inserter; |
| friend class token_joiner; |
| }; |
| |
| class helper_interface |
| { |
| public: |
| |
| virtual void init() { } |
| virtual void reset() { } |
| virtual bool result() { return true; } |
| virtual std::size_t process(generator&) { return 0; } |
| virtual ~helper_interface() { } |
| }; |
| |
| class token_scanner : public helper_interface |
| { |
| public: |
| |
| virtual ~token_scanner() |
| {} |
| |
| explicit token_scanner(const std::size_t& stride) |
| : stride_(stride) |
| { |
| if (stride > 4) |
| { |
| throw std::invalid_argument("token_scanner() - Invalid stride value"); |
| } |
| } |
| |
| inline std::size_t process(generator& g) |
| { |
| if (g.token_list_.size() >= stride_) |
| { |
| for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) |
| { |
| token t; |
| |
| switch (stride_) |
| { |
| case 1 : |
| { |
| const token& t0 = g.token_list_[i]; |
| |
| if (!operator()(t0)) |
| { |
| return i; |
| } |
| } |
| break; |
| |
| case 2 : |
| { |
| const token& t0 = g.token_list_[i ]; |
| const token& t1 = g.token_list_[i + 1]; |
| |
| if (!operator()(t0,t1)) |
| { |
| return i; |
| } |
| } |
| break; |
| |
| case 3 : |
| { |
| const token& t0 = g.token_list_[i ]; |
| const token& t1 = g.token_list_[i + 1]; |
| const token& t2 = g.token_list_[i + 2]; |
| |
| if (!operator()(t0,t1,t2)) |
| { |
| return i; |
| } |
| } |
| break; |
| |
| case 4 : |
| { |
| const token& t0 = g.token_list_[i ]; |
| const token& t1 = g.token_list_[i + 1]; |
| const token& t2 = g.token_list_[i + 2]; |
| const token& t3 = g.token_list_[i + 3]; |
| |
| if (!operator()(t0,t1,t2,t3)) |
| { |
| return i; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| return (g.token_list_.size() - stride_ + 1); |
| } |
| |
| virtual bool operator()(const token&) |
| { |
| return false; |
| } |
| |
| virtual bool operator()(const token&, const token&) |
| { |
| return false; |
| } |
| |
| virtual bool operator()(const token&, const token&, const token&) |
| { |
| return false; |
| } |
| |
| virtual bool operator()(const token&, const token&, const token&, const token&) |
| { |
| return false; |
| } |
| |
| private: |
| |
| std::size_t stride_; |
| }; |
| |
| class token_modifier : public helper_interface |
| { |
| public: |
| |
| inline std::size_t process(generator& g) |
| { |
| std::size_t changes = 0; |
| |
| for (std::size_t i = 0; i < g.token_list_.size(); ++i) |
| { |
| if (modify(g.token_list_[i])) changes++; |
| } |
| |
| return changes; |
| } |
| |
| virtual bool modify(token& t) = 0; |
| }; |
| |
| class token_inserter : public helper_interface |
| { |
| public: |
| |
| explicit token_inserter(const std::size_t& stride) |
| : stride_(stride) |
| { |
| if (stride > 5) |
| { |
| throw std::invalid_argument("token_inserter() - Invalid stride value"); |
| } |
| } |
| |
| inline std::size_t process(generator& g) |
| { |
| if (g.token_list_.empty()) |
| return 0; |
| else if (g.token_list_.size() < stride_) |
| return 0; |
| |
| std::size_t changes = 0; |
| |
| for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) |
| { |
| int insert_index = -1; |
| token t; |
| |
| switch (stride_) |
| { |
| case 1 : insert_index = insert(g.token_list_[i],t); |
| break; |
| |
| case 2 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],t); |
| break; |
| |
| case 3 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t); |
| break; |
| |
| case 4 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],t); |
| break; |
| |
| case 5 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],g.token_list_[i + 4],t); |
| break; |
| } |
| |
| if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1))) |
| { |
| g.token_list_.insert(g.token_list_.begin() + (i + insert_index),t); |
| changes++; |
| } |
| } |
| |
| return changes; |
| } |
| |
| #define token_inserter_empty_body \ |
| { \ |
| return -1; \ |
| } \ |
| |
| inline virtual int insert(const token&, token&) |
| token_inserter_empty_body |
| |
| inline virtual int insert(const token&, const token&, token&) |
| token_inserter_empty_body |
| |
| inline virtual int insert(const token&, const token&, const token&, token&) |
| token_inserter_empty_body |
| |
| inline virtual int insert(const token&, const token&, const token&, const token&, token&) |
| token_inserter_empty_body |
| |
| inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) |
| token_inserter_empty_body |
| |
| #undef token_inserter_empty_body |
| |
| private: |
| |
| std::size_t stride_; |
| }; |
| |
| class token_joiner : public helper_interface |
| { |
| public: |
| |
| token_joiner(const std::size_t& stride) |
| : stride_(stride) |
| {} |
| |
| inline std::size_t process(generator& g) |
| { |
| if (g.token_list_.empty()) |
| return 0; |
| |
| switch (stride_) |
| { |
| case 2 : return process_stride_2(g); |
| case 3 : return process_stride_3(g); |
| default : return 0; |
| } |
| } |
| |
| virtual bool join(const token&, const token&, token&) { return false; } |
| virtual bool join(const token&, const token&, const token&, token&) { return false; } |
| |
| private: |
| |
| inline std::size_t process_stride_2(generator& g) |
| { |
| if (g.token_list_.size() < 2) |
| return 0; |
| |
| std::size_t changes = 0; |
| |
| for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i) |
| { |
| token t; |
| |
| while (join(g[i],g[i + 1],t)) |
| { |
| g.token_list_[i] = t; |
| |
| g.token_list_.erase(g.token_list_.begin() + (i + 1)); |
| |
| ++changes; |
| } |
| } |
| |
| return changes; |
| } |
| |
| inline std::size_t process_stride_3(generator& g) |
| { |
| if (g.token_list_.size() < 3) |
| return 0; |
| |
| std::size_t changes = 0; |
| |
| for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i) |
| { |
| token t; |
| |
| while (join(g[i],g[i + 1],g[i + 2],t)) |
| { |
| g.token_list_[i] = t; |
| |
| g.token_list_.erase(g.token_list_.begin() + (i + 1), |
| g.token_list_.begin() + (i + 3)); |
| ++changes; |
| } |
| } |
| |
| return changes; |
| } |
| |
| std::size_t stride_; |
| }; |
| |
| namespace helper |
| { |
| |
| inline void dump(lexer::generator& generator) |
| { |
| for (std::size_t i = 0; i < generator.size(); ++i) |
| { |
| lexer::token t = generator[i]; |
| printf("Token[%02d] @ %03d %6s --> '%s'\n", |
| static_cast<int>(i), |
| static_cast<int>(t.position), |
| t.to_str(t.type).c_str(), |
| t.value.c_str()); |
| } |
| } |
| |
| class commutative_inserter : public lexer::token_inserter |
| { |
| public: |
| |
| using lexer::token_inserter::insert; |
| |
| commutative_inserter() |
| : lexer::token_inserter(2) |
| {} |
| |
| inline void ignore_symbol(const std::string& symbol) |
| { |
| ignore_set_.insert(symbol); |
| } |
| |
| inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) |
| { |
| bool match = false; |
| new_token.type = lexer::token::e_mul; |
| new_token.value = "*"; |
| new_token.position = t1.position; |
| |
| if (t0.type == lexer::token::e_symbol) |
| { |
| if (ignore_set_.end() != ignore_set_.find(t0.value)) |
| { |
| return -1; |
| } |
| else if (!t0.value.empty() && ('$' == t0.value[0])) |
| { |
| return -1; |
| } |
| } |
| |
| if (t1.type == lexer::token::e_symbol) |
| { |
| if (ignore_set_.end() != ignore_set_.find(t1.value)) |
| { |
| return -1; |
| } |
| } |
| if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; |
| else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; |
| else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; |
| else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; |
| else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; |
| else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; |
| else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; |
| else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; |
| else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; |
| else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; |
| else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; |
| |
| return (match) ? 1 : -1; |
| } |
| |
| private: |
| |
| std::set<std::string,details::ilesscompare> ignore_set_; |
| }; |
| |
| class operator_joiner : public token_joiner |
| { |
| public: |
| |
| operator_joiner(const std::size_t& stride) |
| : token_joiner(stride) |
| {} |
| |
| inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) |
| { |
| // ': =' --> ':=' |
| if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_assign; |
| t.value = ":="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '+ =' --> '+=' |
| else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_addass; |
| t.value = "+="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '- =' --> '-=' |
| else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_subass; |
| t.value = "-="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '* =' --> '*=' |
| else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_mulass; |
| t.value = "*="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '/ =' --> '/=' |
| else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_divass; |
| t.value = "/="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '% =' --> '%=' |
| else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_modass; |
| t.value = "%="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '> =' --> '>=' |
| else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_gte; |
| t.value = ">="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '< =' --> '<=' |
| else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_lte; |
| t.value = "<="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '= =' --> '==' |
| else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_eq; |
| t.value = "=="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '! =' --> '!=' |
| else if ((static_cast<char>(t0.type) == '!') && (t1.type == lexer::token::e_eq)) |
| { |
| t.type = lexer::token::e_ne; |
| t.value = "!="; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '< >' --> '<>' |
| else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) |
| { |
| t.type = lexer::token::e_ne; |
| t.value = "<>"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '<= >' --> '<=>' |
| else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) |
| { |
| t.type = lexer::token::e_swap; |
| t.value = "<=>"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '+ -' --> '-' |
| else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) |
| { |
| t.type = lexer::token::e_sub; |
| t.value = "-"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '- +' --> '-' |
| else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) |
| { |
| t.type = lexer::token::e_sub; |
| t.value = "-"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| // '- -' --> '-' |
| else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) |
| { |
| /* |
| Note: May need to reconsider this when wanting to implement |
| pre/postfix decrement operator |
| */ |
| t.type = lexer::token::e_add; |
| t.value = "+"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) |
| { |
| // '[ * ]' --> '[*]' |
| if ( |
| (t0.type == lexer::token::e_lsqrbracket) && |
| (t1.type == lexer::token::e_mul ) && |
| (t2.type == lexer::token::e_rsqrbracket) |
| ) |
| { |
| t.type = lexer::token::e_symbol; |
| t.value = "[*]"; |
| t.position = t0.position; |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| }; |
| |
| class bracket_checker : public lexer::token_scanner |
| { |
| public: |
| |
| using lexer::token_scanner::operator(); |
| |
| bracket_checker() |
| : token_scanner(1), |
| state_(true) |
| {} |
| |
| bool result() |
| { |
| if (!stack_.empty()) |
| { |
| lexer::token t; |
| t.value = stack_.top().first; |
| t.position = stack_.top().second; |
| error_token_ = t; |
| state_ = false; |
| |
| return false; |
| } |
| else |
| return state_; |
| } |
| |
| lexer::token error_token() |
| { |
| return error_token_; |
| } |
| |
| void reset() |
| { |
| // Why? because msvc doesn't support swap properly. |
| stack_ = std::stack<std::pair<char,std::size_t> >(); |
| state_ = true; |
| error_token_.clear(); |
| } |
| |
| bool operator()(const lexer::token& t) |
| { |
| if ( |
| !t.value.empty() && |
| (lexer::token::e_string != t.type) && |
| (lexer::token::e_symbol != t.type) && |
| exprtk::details::is_bracket(t.value[0]) |
| ) |
| { |
| details::char_t c = t.value[0]; |
| |
| if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); |
| else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); |
| else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); |
| else if (exprtk::details::is_right_bracket(c)) |
| { |
| if (stack_.empty()) |
| { |
| state_ = false; |
| error_token_ = t; |
| |
| return false; |
| } |
| else if (c != stack_.top().first) |
| { |
| state_ = false; |
| error_token_ = t; |
| |
| return false; |
| } |
| else |
| stack_.pop(); |
| } |
| } |
| |
| return true; |
| } |
| |
| private: |
| |
| bool state_; |
| std::stack<std::pair<char,std::size_t> > stack_; |
| lexer::token error_token_; |
| }; |
| |
| class numeric_checker : public lexer::token_scanner |
| { |
| public: |
| |
| using lexer::token_scanner::operator(); |
| |
| numeric_checker() |
| : token_scanner (1), |
| current_index_(0) |
| {} |
| |
| bool result() |
| { |
| return error_list_.empty(); |
| } |
| |
| void reset() |
| { |
| error_list_.clear(); |
| current_index_ = 0; |
| } |
| |
| bool operator()(const lexer::token& t) |
| { |
| if (token::e_number == t.type) |
| { |
| double v; |
| |
| if (!exprtk::details::string_to_real(t.value,v)) |
| { |
| error_list_.push_back(current_index_); |
| } |
| } |
| |
| ++current_index_; |
| |
| return true; |
| } |
| |
| std::size_t error_count() const |
| { |
| return error_list_.size(); |
| } |
| |
| std::size_t error_index(const std::size_t& i) |
| { |
| if (i < error_list_.size()) |
| return error_list_[i]; |
| else |
| return std::numeric_limits<std::size_t>::max(); |
| } |
| |
| void clear_errors() |
| { |
| error_list_.clear(); |
| } |
| |
| private: |
| |
| std::size_t current_index_; |
| std::vector<std::size_t> error_list_; |
| }; |
| |
| class symbol_replacer : public lexer::token_modifier |
| { |
| private: |
| |
| typedef std::map<std::string,std::pair<std::string,token::token_type>,details::ilesscompare> replace_map_t; |
| |
| public: |
| |
| bool remove(const std::string& target_symbol) |
| { |
| replace_map_t::iterator itr = replace_map_.find(target_symbol); |
| |
| if (replace_map_.end() == itr) |
| return false; |
| |
| replace_map_.erase(itr); |
| |
| return true; |
| } |
| |
| bool add_replace(const std::string& target_symbol, |
| const std::string& replace_symbol, |
| const lexer::token::token_type token_type = lexer::token::e_symbol) |
| { |
| replace_map_t::iterator itr = replace_map_.find(target_symbol); |
| |
| if (replace_map_.end() != itr) |
| { |
| return false; |
| } |
| |
| replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type); |
| |
| return true; |
| } |
| |
| void clear() |
| { |
| replace_map_.clear(); |
| } |
| |
| private: |
| |
| bool modify(lexer::token& t) |
| { |
| if (lexer::token::e_symbol == t.type) |
| { |
| if (replace_map_.empty()) |
| return false; |
| |
| replace_map_t::iterator itr = replace_map_.find(t.value); |
| |
| if (replace_map_.end() != itr) |
| { |
| t.value = itr->second.first; |
| t.type = itr->second.second; |
| |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| replace_map_t replace_map_; |
| }; |
| |
| class sequence_validator : public lexer::token_scanner |
| { |
| private: |
| |
| typedef std::pair<lexer::token::token_type,lexer::token::token_type> token_pair_t; |
| typedef std::set<token_pair_t> set_t; |
| |
| public: |
| |
| using lexer::token_scanner::operator(); |
| |
| sequence_validator() |
| : lexer::token_scanner(2) |
| { |
| add_invalid(lexer::token::e_number ,lexer::token::e_number ); |
| add_invalid(lexer::token::e_string ,lexer::token::e_string ); |
| add_invalid(lexer::token::e_number ,lexer::token::e_string ); |
| add_invalid(lexer::token::e_string ,lexer::token::e_number ); |
| add_invalid(lexer::token::e_string ,lexer::token::e_ternary); |
| add_invalid_set1(lexer::token::e_assign ); |
| add_invalid_set1(lexer::token::e_shr ); |
| add_invalid_set1(lexer::token::e_shl ); |
| add_invalid_set1(lexer::token::e_lte ); |
| add_invalid_set1(lexer::token::e_ne ); |
| add_invalid_set1(lexer::token::e_gte ); |
| add_invalid_set1(lexer::token::e_lt ); |
| add_invalid_set1(lexer::token::e_gt ); |
| add_invalid_set1(lexer::token::e_eq ); |
| add_invalid_set1(lexer::token::e_comma ); |
| add_invalid_set1(lexer::token::e_add ); |
| add_invalid_set1(lexer::token::e_sub ); |
| add_invalid_set1(lexer::token::e_div ); |
| add_invalid_set1(lexer::token::e_mul ); |
| add_invalid_set1(lexer::token::e_mod ); |
| add_invalid_set1(lexer::token::e_pow ); |
| add_invalid_set1(lexer::token::e_colon ); |
| add_invalid_set1(lexer::token::e_ternary); |
| } |
| |
| bool result() |
| { |
| return error_list_.empty(); |
| } |
| |
| bool operator()(const lexer::token& t0, const lexer::token& t1) |
| { |
| set_t::value_type p = std::make_pair(t0.type,t1.type); |
| |
| if (invalid_bracket_check(t0.type,t1.type)) |
| { |
| error_list_.push_back(std::make_pair(t0,t1)); |
| } |
| else if (invalid_comb_.find(p) != invalid_comb_.end()) |
| { |
| error_list_.push_back(std::make_pair(t0,t1)); |
| } |
| |
| return true; |
| } |
| |
| std::size_t error_count() |
| { |
| return error_list_.size(); |
| } |
| |
| std::pair<lexer::token,lexer::token> error(const std::size_t index) |
| { |
| if (index < error_list_.size()) |
| { |
| return error_list_[index]; |
| } |
| else |
| { |
| static const lexer::token error_token; |
| return std::make_pair(error_token,error_token); |
| } |
| } |
| |
| void clear_errors() |
| { |
| error_list_.clear(); |
| } |
| |
| private: |
| |
| void add_invalid(lexer::token::token_type base, lexer::token::token_type t) |
| { |
| invalid_comb_.insert(std::make_pair(base,t)); |
| } |
| |
| void add_invalid_set1(lexer::token::token_type t) |
| { |
| add_invalid(t,lexer::token::e_assign); |
| add_invalid(t,lexer::token::e_shr ); |
| add_invalid(t,lexer::token::e_shl ); |
| add_invalid(t,lexer::token::e_lte ); |
| add_invalid(t,lexer::token::e_ne ); |
| add_invalid(t,lexer::token::e_gte ); |
| add_invalid(t,lexer::token::e_lt ); |
| add_invalid(t,lexer::token::e_gt ); |
| add_invalid(t,lexer::token::e_eq ); |
| add_invalid(t,lexer::token::e_comma ); |
| add_invalid(t,lexer::token::e_div ); |
| add_invalid(t,lexer::token::e_mul ); |
| add_invalid(t,lexer::token::e_mod ); |
| add_invalid(t,lexer::token::e_pow ); |
| add_invalid(t,lexer::token::e_colon ); |
| } |
| |
| bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t) |
| { |
| if (details::is_right_bracket(static_cast<char>(base))) |
| { |
| switch (t) |
| { |
| case lexer::token::e_assign : return (']' != base); |
| case lexer::token::e_string : return true; |
| default : return false; |
| } |
| } |
| else if (details::is_left_bracket(static_cast<char>(base))) |
| { |
| if (details::is_right_bracket(static_cast<char>(t))) |
| return false; |
| else if (details::is_left_bracket(static_cast<char>(t))) |
| return false; |
| else |
| { |
| switch (t) |
| { |
| case lexer::token::e_number : return false; |
| case lexer::token::e_symbol : return false; |
| case lexer::token::e_string : return false; |
| case lexer::token::e_add : return false; |
| case lexer::token::e_sub : return false; |
| case lexer::token::e_colon : return false; |
| case lexer::token::e_ternary : return false; |
| default : return true; |
| } |
| } |
| } |
| else if (details::is_right_bracket(static_cast<char>(t))) |
| { |
| switch (base) |
| { |
| case lexer::token::e_number : return false; |
| case lexer::token::e_symbol : return false; |
| case lexer::token::e_string : return false; |
| case lexer::token::e_eof : return false; |
| case lexer::token::e_colon : return false; |
| case lexer::token::e_ternary : return false; |
| default : return true; |
| } |
| } |
| else if (details::is_left_bracket(static_cast<char>(t))) |
| { |
| switch (base) |
| { |
| case lexer::token::e_rbracket : return true; |
| case lexer::token::e_rsqrbracket : return true; |
| case lexer::token::e_rcrlbracket : return true; |
| default : return false; |
| } |
| } |
| |
| return false; |
| } |
| |
| set_t invalid_comb_; |
| std::vector<std::pair<lexer::token,lexer::token> > error_list_; |
| }; |
| |
| struct helper_assembly |
| { |
| inline bool register_scanner(lexer::token_scanner* scanner) |
| { |
| if (token_scanner_list.end() != std::find(token_scanner_list.begin(), |
| token_scanner_list.end(), |
| scanner)) |
| { |
| return false; |
| } |
| |
| token_scanner_list.push_back(scanner); |
| |
| return true; |
| } |
| |
| inline bool register_modifier(lexer::token_modifier* modifier) |
| { |
| if (token_modifier_list.end() != std::find(token_modifier_list.begin(), |
| token_modifier_list.end(), |
| modifier)) |
| { |
| return false; |
| } |
| |
| token_modifier_list.push_back(modifier); |
| |
| return true; |
| } |
| |
| inline bool register_joiner(lexer::token_joiner* joiner) |
| { |
| if (token_joiner_list.end() != std::find(token_joiner_list.begin(), |
| token_joiner_list.end(), |
| joiner)) |
| { |
| return false; |
| } |
| |
| token_joiner_list.push_back(joiner); |
| |
| return true; |
| } |
| |
| inline bool register_inserter(lexer::token_inserter* inserter) |
| { |
| if (token_inserter_list.end() != std::find(token_inserter_list.begin(), |
| token_inserter_list.end(), |
| inserter)) |
| { |
| return false; |
| } |
| |
| token_inserter_list.push_back(inserter); |
| |
| return true; |
| } |
| |
| inline bool run_modifiers(lexer::generator& g) |
| { |
| error_token_modifier = reinterpret_cast<lexer::token_modifier*>(0); |
| |
| for (std::size_t i = 0; i < token_modifier_list.size(); ++i) |
| { |
| lexer::token_modifier& modifier = (*token_modifier_list[i]); |
| |
| modifier.reset(); |
| modifier.process(g); |
| |
| if (!modifier.result()) |
| { |
| error_token_modifier = token_modifier_list[i]; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| inline bool run_joiners(lexer::generator& g) |
| { |
| error_token_joiner = reinterpret_cast<lexer::token_joiner*>(0); |
| |
| for (std::size_t i = 0; i < token_joiner_list.size(); ++i) |
| { |
| lexer::token_joiner& joiner = (*token_joiner_list[i]); |
| |
| joiner.reset(); |
| joiner.process(g); |
| |
| if (!joiner.result()) |
| { |
| error_token_joiner = token_joiner_list[i]; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| inline bool run_inserters(lexer::generator& g) |
| { |
| error_token_inserter = reinterpret_cast<lexer::token_inserter*>(0); |
| |
| for (std::size_t i = 0; i < token_inserter_list.size(); ++i) |
| { |
| lexer::token_inserter& inserter = (*token_inserter_list[i]); |
| |
| inserter.reset(); |
| inserter.process(g); |
| |
| if (!inserter.result()) |
| { |
| error_token_inserter = token_inserter_list[i]; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| inline bool run_scanners(lexer::generator& g) |
| { |
| error_token_scanner = reinterpret_cast<lexer::token_scanner*>(0); |
| |
| for (std::size_t i = 0; i < token_scanner_list.size(); ++i) |
| { |
| lexer::token_scanner& scanner = (*token_scanner_list[i]); |
| |
| scanner.reset(); |
| scanner.process(g); |
| |
| if (!scanner.result()) |
| { |
| error_token_scanner = token_scanner_list[i]; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| std::vector<lexer::token_scanner*> token_scanner_list; |
| std::vector<lexer::token_modifier*> token_modifier_list; |
| std::vector<lexer::token_joiner*> token_joiner_list; |
| std::vector<lexer::token_inserter*> token_inserter_list; |
| |
| lexer::token_scanner* error_token_scanner; |
| lexer::token_modifier* error_token_modifier; |
| lexer::token_joiner* error_token_joiner; |
| lexer::token_inserter* error_token_inserter; |
| }; |
| } |
| |
| class parser_helper |
| { |
| public: |
| |
| typedef token token_t; |
| typedef generator generator_t; |
| |
| inline bool init(const std::string& str) |
| { |
| if (!lexer_.process(str)) |
| { |
| return false; |
| } |
| |
| lexer_.begin(); |
| |
| next_token(); |
| |
| return true; |
| } |
| |
| inline generator_t& lexer() |
| { |
| return lexer_; |
| } |
| |
| inline const generator_t& lexer() const |
| { |
| return lexer_; |
| } |
| |
| inline void store_token() |
| { |
| lexer_.store(); |
| store_current_token_ = current_token_; |
| } |
| |
| inline void restore_token() |
| { |
| lexer_.restore(); |
| current_token_ = store_current_token_; |
| } |
| |
| inline void next_token() |
| { |
| current_token_ = lexer_.next_token(); |
| } |
| |
| inline const token_t& current_token() const |
| { |
| return current_token_; |
| } |
| |
| enum token_advance_mode |
| { |
| e_hold = 0, |
| e_advance = 1 |
| }; |
| |
| inline void advance_token(const token_advance_mode mode) |
| { |
| if (e_advance == mode) |
| { |
| next_token(); |
| } |
| } |
| |
| inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) |
| { |
| if (current_token().type != ttype) |
| { |
| return false; |
| } |
| |
| advance_token(mode); |
| |
| return true; |
| } |
| |
| inline bool token_is(const token_t::token_type& ttype, |
| const std::string& value, |
| const token_advance_mode mode = e_advance) |
| { |
| if ( |
| (current_token().type != ttype) || |
| !exprtk::details::imatch(value,current_token().value) |
| ) |
| { |
| return false; |
| } |
| |
| advance_token(mode); |
| |
| return true; |
| } |
| |
| inline bool token_is_then_assign(const token_t::token_type& ttype, |
| std::string& token, |
| const token_advance_mode mode = e_advance) |
| { |
| if (current_token_.type != ttype) |
| { |
| return false; |
| } |
| |
| token = current_token_.value; |
| |
| advance_token(mode); |
| |
| return true; |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Container> |
| inline bool token_is_then_assign(const token_t::token_type& ttype, |
| Container<std::string,Allocator>& token_list, |
| const token_advance_mode mode = e_advance) |
| { |
| if (current_token_.type != ttype) |
| { |
| return false; |
| } |
| |
| token_list.push_back(current_token_.value); |
| |
| advance_token(mode); |
| |
| return true; |
| } |
| |
| inline bool peek_token_is(const token_t::token_type& ttype) |
| { |
| return (lexer_.peek_next_token().type == ttype); |
| } |
| |
| inline bool peek_token_is(const std::string& s) |
| { |
| return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); |
| } |
| |
| private: |
| |
| generator_t lexer_; |
| token_t current_token_; |
| token_t store_current_token_; |
| }; |
| } |
| |
| template <typename T> |
| class vector_view |
| { |
| public: |
| |
| typedef T* data_ptr_t; |
| |
| vector_view(data_ptr_t data, const std::size_t& size) |
| : size_(size), |
| data_(data), |
| data_ref_(0) |
| {} |
| |
| vector_view(const vector_view<T>& vv) |
| : size_(vv.size_), |
| data_(vv.data_), |
| data_ref_(0) |
| {} |
| |
| inline void rebase(data_ptr_t data) |
| { |
| data_ = data; |
| |
| if (!data_ref_.empty()) |
| { |
| for (std::size_t i = 0; i < data_ref_.size(); ++i) |
| { |
| (*data_ref_[i]) = data; |
| } |
| } |
| } |
| |
| inline data_ptr_t data() const |
| { |
| return data_; |
| } |
| |
| inline std::size_t size() const |
| { |
| return size_; |
| } |
| |
| inline const T& operator[](const std::size_t index) const |
| { |
| return data_[index]; |
| } |
| |
| inline T& operator[](const std::size_t index) |
| { |
| return data_[index]; |
| } |
| |
| void set_ref(data_ptr_t* data_ref) |
| { |
| data_ref_.push_back(data_ref); |
| } |
| |
| private: |
| |
| std::size_t size_; |
| data_ptr_t data_; |
| std::vector<data_ptr_t*> data_ref_; |
| }; |
| |
| template <typename T> |
| inline vector_view<T> make_vector_view(T* data, |
| const std::size_t size, const std::size_t offset = 0) |
| { |
| return vector_view<T>(data + offset,size); |
| } |
| |
| template <typename T> |
| inline vector_view<T> make_vector_view(std::vector<T>& v, |
| const std::size_t size, const std::size_t offset = 0) |
| { |
| return vector_view<T>(v.data() + offset,size); |
| } |
| |
| template <typename T> class results_context; |
| |
| template <typename T> |
| struct type_store |
| { |
| enum store_type |
| { |
| e_unknown, |
| e_scalar, |
| e_vector, |
| e_string |
| }; |
| |
| type_store() |
| : size(0), |
| data(0), |
| type(e_unknown) |
| {} |
| |
| std::size_t size; |
| void* data; |
| store_type type; |
| |
| class parameter_list |
| { |
| public: |
| |
| parameter_list(std::vector<type_store>& pl) |
| : parameter_list_(pl) |
| {} |
| |
| inline bool empty() const |
| { |
| return parameter_list_.empty(); |
| } |
| |
| inline std::size_t size() const |
| { |
| return parameter_list_.size(); |
| } |
| |
| inline type_store& operator[](const std::size_t& index) |
| { |
| return parameter_list_[index]; |
| } |
| |
| inline const type_store& operator[](const std::size_t& index) const |
| { |
| return parameter_list_[index]; |
| } |
| |
| inline type_store& front() |
| { |
| return parameter_list_[0]; |
| } |
| |
| inline const type_store& front() const |
| { |
| return parameter_list_[0]; |
| } |
| |
| inline type_store& back() |
| { |
| return parameter_list_.back(); |
| } |
| |
| inline const type_store& back() const |
| { |
| return parameter_list_.back(); |
| } |
| |
| private: |
| |
| std::vector<type_store>& parameter_list_; |
| |
| friend class results_context<T>; |
| }; |
| |
| template <typename ViewType> |
| struct type_view |
| { |
| typedef type_store<T> type_store_t; |
| typedef ViewType value_t; |
| |
| type_view(type_store_t& ts) |
| : ts_(ts), |
| data_(reinterpret_cast<value_t*>(ts_.data)) |
| {} |
| |
| inline std::size_t size() const |
| { |
| return ts_.size; |
| } |
| |
| inline value_t& operator[](const std::size_t& i) |
| { |
| return data_[i]; |
| } |
| |
| inline const value_t& operator[](const std::size_t& i) const |
| { |
| return data_[i]; |
| } |
| |
| inline const value_t* begin() const { return data_; } |
| inline value_t* begin() { return data_; } |
| |
| inline const value_t* end() const |
| { |
| return static_cast<value_t*>(data_ + ts_.size); |
| } |
| |
| inline value_t* end() |
| { |
| return static_cast<value_t*>(data_ + ts_.size); |
| } |
| |
| type_store_t& ts_; |
| value_t* data_; |
| }; |
| |
| typedef type_view<T> vector_view; |
| typedef type_view<char> string_view; |
| |
| struct scalar_view |
| { |
| typedef type_store<T> type_store_t; |
| typedef T value_t; |
| |
| scalar_view(type_store_t& ts) |
| : v_(*reinterpret_cast<value_t*>(ts.data)) |
| {} |
| |
| scalar_view(const type_store_t& ts) |
| : v_(*reinterpret_cast<value_t*>(const_cast<type_store_t&>(ts).data)) |
| {} |
| |
| inline value_t& operator()() |
| { |
| return v_; |
| } |
| |
| inline const value_t& operator()() const |
| { |
| return v_; |
| } |
| |
| template <typename IntType> |
| inline bool to_int(IntType& i) const |
| { |
| if (!exprtk::details::numeric::is_integer(v_)) |
| return false; |
| |
| i = static_cast<IntType>(v_); |
| |
| return true; |
| } |
| |
| template <typename UIntType> |
| inline bool to_uint(UIntType& u) const |
| { |
| if (v_ < T(0)) |
| return false; |
| else if (!exprtk::details::numeric::is_integer(v_)) |
| return false; |
| |
| u = static_cast<UIntType>(v_); |
| |
| return true; |
| } |
| |
| T& v_; |
| }; |
| }; |
| |
| template <typename StringView> |
| inline std::string to_str(const StringView& view) |
| { |
| return std::string(view.begin(),view.size()); |
| } |
| |
| namespace details |
| { |
| template <typename T> class return_node; |
| template <typename T> class return_envelope_node; |
| } |
| |
| template <typename T> |
| class results_context |
| { |
| public: |
| |
| typedef type_store<T> type_store_t; |
| |
| results_context() |
| : results_available_(false) |
| {} |
| |
| inline std::size_t count() const |
| { |
| if (results_available_) |
| return parameter_list_.size(); |
| else |
| return 0; |
| } |
| |
| inline type_store_t& operator[](const std::size_t& index) |
| { |
| return parameter_list_[index]; |
| } |
| |
| inline const type_store_t& operator[](const std::size_t& index) const |
| { |
| return parameter_list_[index]; |
| } |
| |
| private: |
| |
| inline void clear() |
| { |
| results_available_ = false; |
| } |
| |
| typedef std::vector<type_store_t> ts_list_t; |
| typedef typename type_store_t::parameter_list parameter_list_t; |
| |
| inline void assign(const parameter_list_t& pl) |
| { |
| parameter_list_ = pl.parameter_list_; |
| results_available_ = true; |
| } |
| |
| bool results_available_; |
| ts_list_t parameter_list_; |
| |
| friend class details::return_node<T>; |
| friend class details::return_envelope_node<T>; |
| }; |
| |
| namespace details |
| { |
| enum operator_type |
| { |
| e_default , e_null , e_add , e_sub , |
| e_mul , e_div , e_mod , e_pow , |
| e_atan2 , e_min , e_max , e_avg , |
| e_sum , e_prod , e_lt , e_lte , |
| e_eq , e_equal , e_ne , e_nequal , |
| e_gte , e_gt , e_and , e_nand , |
| e_or , e_nor , e_xor , e_xnor , |
| e_mand , e_mor , e_scand , e_scor , |
| e_shr , e_shl , e_abs , e_acos , |
| e_acosh , e_asin , e_asinh , e_atan , |
| e_atanh , e_ceil , e_cos , e_cosh , |
| e_exp , e_expm1 , e_floor , e_log , |
| e_log10 , e_log2 , e_log1p , e_logn , |
| e_neg , e_pos , e_round , e_roundn , |
| e_root , e_sqrt , e_sin , e_sinc , |
| e_sinh , e_sec , e_csc , e_tan , |
| e_tanh , e_cot , e_clamp , e_iclamp , |
| e_inrange , e_sgn , e_r2d , e_d2r , |
| e_d2g , e_g2d , e_hypot , e_notl , |
| e_erf , e_erfc , e_ncdf , e_frac , |
| e_trunc , e_assign , e_addass , e_subass , |
| e_mulass , e_divass , e_modass , e_in , |
| e_like , e_ilike , e_multi , e_swap , |
| |
| // Do not add new functions/operators after this point. |
| e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, |
| e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, |
| e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, |
| e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, |
| e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, |
| e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, |
| e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, |
| e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, |
| e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, |
| e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, |
| e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, |
| e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, |
| e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, |
| e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, |
| e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, |
| e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, |
| e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, |
| e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, |
| e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, |
| e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, |
| e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, |
| e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, |
| e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, |
| e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, |
| e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, |
| e_sffinal = 1100, |
| e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, |
| e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, |
| e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, |
| e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, |
| e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, |
| e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, |
| e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, |
| e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, |
| e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, |
| e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, |
| e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, |
| e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, |
| e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, |
| e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, |
| e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, |
| e_sf4ext60 = 2060 |
| }; |
| |
| inline std::string to_str(const operator_type opr) |
| { |
| switch (opr) |
| { |
| case e_add : return "+"; |
| case e_sub : return "-"; |
| case e_mul : return "*"; |
| case e_div : return "/"; |
| case e_mod : return "%"; |
| case e_pow : return "^"; |
| case e_assign : return ":="; |
| case e_addass : return "+="; |
| case e_subass : return "-="; |
| case e_mulass : return "*="; |
| case e_divass : return "/="; |
| case e_modass : return "%="; |
| case e_lt : return "<"; |
| case e_lte : return "<="; |
| case e_eq : return "=="; |
| case e_equal : return "="; |
| case e_ne : return "!="; |
| case e_nequal : return "<>"; |
| case e_gte : return ">="; |
| case e_gt : return ">"; |
| default : return"N/A"; |
| } |
| } |
| |
| struct base_operation_t |
| { |
| base_operation_t(const operator_type t, const unsigned int& np) |
| : type(t), |
| num_params(np) |
| {} |
| |
| operator_type type; |
| unsigned int num_params; |
| }; |
| |
| namespace loop_unroll |
| { |
| #ifndef exprtk_disable_superscalar_unroll |
| const unsigned int global_loop_batch_size = 16; |
| #else |
| const unsigned int global_loop_batch_size = 4; |
| #endif |
| |
| struct details |
| { |
| details(const std::size_t& vsize, |
| const unsigned int loop_batch_size = global_loop_batch_size) |
| : batch_size(loop_batch_size), |
| remainder (vsize % batch_size), |
| upper_bound(static_cast<int>(vsize) - (remainder ? loop_batch_size : 0)) |
| {} |
| |
| int batch_size; |
| int remainder; |
| int upper_bound; |
| }; |
| } |
| |
| #ifdef exprtk_enable_debugging |
| inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) |
| { |
| if (size) |
| exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); |
| else |
| exprtk_debug(("%s - addr: %p size: %d\n", |
| s.c_str(), |
| ptr, |
| static_cast<unsigned int>(size))); |
| } |
| #else |
| inline void dump_ptr(const std::string&, const void*) {} |
| inline void dump_ptr(const std::string&, const void*, const std::size_t) {} |
| #endif |
| |
| template <typename T> |
| class vec_data_store |
| { |
| public: |
| |
| typedef vec_data_store<T> type; |
| typedef T* data_t; |
| |
| private: |
| |
| struct control_block |
| { |
| control_block() |
| : ref_count(1), |
| size (0), |
| data (0), |
| destruct (true) |
| {} |
| |
| control_block(const std::size_t& dsize) |
| : ref_count(1), |
| size (dsize), |
| data (0), |
| destruct (true) |
| { create_data(); } |
| |
| control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) |
| : ref_count(1), |
| size (dsize), |
| data (dptr ), |
| destruct (dstrct) |
| {} |
| |
| ~control_block() |
| { |
| if (data && destruct && (0 == ref_count)) |
| { |
| dump_ptr("~control_block() data",data); |
| delete[] data; |
| data = 0; |
| } |
| } |
| |
| static inline control_block* create(const std::size_t& size, data_t data_ptr = data_t(0), bool dstrct = false) |
| { |
| if (size) |
| { |
| if (0 == data_ptr) |
| return new control_block(size); |
| else |
| return new control_block(size, data_ptr, dstrct); |
| } |
| else |
| return new control_block; |
| } |
| |
| static inline void destroy(control_block*& cntrl_blck) |
| { |
| if (cntrl_blck) |
| { |
| if ( |
| (0 != cntrl_blck->ref_count) && |
| (0 == --cntrl_blck->ref_count) |
| ) |
| { |
| delete cntrl_blck; |
| } |
| |
| cntrl_blck = 0; |
| } |
| } |
| |
| std::size_t ref_count; |
| std::size_t size; |
| data_t data; |
| bool destruct; |
| |
| private: |
| |
| control_block(const control_block&); |
| control_block& operator=(const control_block&); |
| |
| inline void create_data() |
| { |
| destruct = true; |
| data = new T[size]; |
| std::fill_n(data,size,T(0)); |
| dump_ptr("control_block::create_data() - data",data,size); |
| } |
| }; |
| |
| public: |
| |
| vec_data_store() |
| : control_block_(control_block::create(0)) |
| {} |
| |
| vec_data_store(const std::size_t& size) |
| : control_block_(control_block::create(size,(data_t)(0),true)) |
| {} |
| |
| vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) |
| : control_block_(control_block::create(size, data, dstrct)) |
| {} |
| |
| vec_data_store(const type& vds) |
| { |
| control_block_ = vds.control_block_; |
| control_block_->ref_count++; |
| } |
| |
| ~vec_data_store() |
| { |
| control_block::destroy(control_block_); |
| } |
| |
| type& operator=(const type& vds) |
| { |
| if (this != &vds) |
| { |
| std::size_t final_size = min_size(control_block_, vds.control_block_); |
| |
| vds.control_block_->size = final_size; |
| control_block_->size = final_size; |
| |
| if (control_block_->destruct || (0 == control_block_->data)) |
| { |
| control_block::destroy(control_block_); |
| |
| control_block_ = vds.control_block_; |
| control_block_->ref_count++; |
| } |
| } |
| |
| return *this; |
| } |
| |
| inline data_t data() |
| { |
| return control_block_->data; |
| } |
| |
| inline data_t data() const |
| { |
| return control_block_->data; |
| } |
| |
| inline std::size_t size() |
| { |
| return control_block_->size; |
| } |
| |
| inline std::size_t size() const |
| { |
| return control_block_->size; |
| } |
| |
| inline data_t& ref() |
| { |
| return control_block_->data; |
| } |
| |
| inline void dump() const |
| { |
| #ifdef exprtk_enable_debugging |
| exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", |
| size(), |
| data(), |
| (control_block_->destruct ? 'T' : 'F'))); |
| |
| for (std::size_t i = 0; i < size(); ++i) |
| { |
| if (5 == i) |
| exprtk_debug(("\n")); |
| |
| exprtk_debug(("%15.10f ",data()[i])); |
| } |
| exprtk_debug(("\n")); |
| #endif |
| } |
| |
| static inline void match_sizes(type& vds0, type& vds1) |
| { |
| std::size_t size = min_size(vds0.control_block_,vds1.control_block_); |
| vds0.control_block_->size = size; |
| vds1.control_block_->size = size; |
| } |
| |
| private: |
| |
| static inline std::size_t min_size(control_block* cb0, control_block* cb1) |
| { |
| std::size_t size0 = cb0->size; |
| std::size_t size1 = cb1->size; |
| |
| if (size0 && size1) |
| return std::min(size0,size1); |
| else |
| return (size0) ? size0 : size1; |
| } |
| |
| control_block* control_block_; |
| }; |
| |
| namespace numeric |
| { |
| namespace details |
| { |
| template <typename T> |
| inline T process_impl(const operator_type operation, const T arg) |
| { |
| switch (operation) |
| { |
| case e_abs : return numeric::abs (arg); |
| case e_acos : return numeric::acos (arg); |
| case e_acosh : return numeric::acosh(arg); |
| case e_asin : return numeric::asin (arg); |
| case e_asinh : return numeric::asinh(arg); |
| case e_atan : return numeric::atan (arg); |
| case e_atanh : return numeric::atanh(arg); |
| case e_ceil : return numeric::ceil (arg); |
| case e_cos : return numeric::cos (arg); |
| case e_cosh : return numeric::cosh (arg); |
| case e_exp : return numeric::exp (arg); |
| case e_expm1 : return numeric::expm1(arg); |
| case e_floor : return numeric::floor(arg); |
| case e_log : return numeric::log (arg); |
| case e_log10 : return numeric::log10(arg); |
| case e_log2 : return numeric::log2 (arg); |
| case e_log1p : return numeric::log1p(arg); |
| case e_neg : return numeric::neg (arg); |
| case e_pos : return numeric::pos (arg); |
| case e_round : return numeric::round(arg); |
| case e_sin : return numeric::sin (arg); |
| case e_sinc : return numeric::sinc (arg); |
| case e_sinh : return numeric::sinh (arg); |
| case e_sqrt : return numeric::sqrt (arg); |
| case e_tan : return numeric::tan (arg); |
| case e_tanh : return numeric::tanh (arg); |
| case e_cot : return numeric::cot (arg); |
| case e_sec : return numeric::sec (arg); |
| case e_csc : return numeric::csc (arg); |
| case e_r2d : return numeric::r2d (arg); |
| case e_d2r : return numeric::d2r (arg); |
| case e_d2g : return numeric::d2g (arg); |
| case e_g2d : return numeric::g2d (arg); |
| case e_notl : return numeric::notl (arg); |
| case e_sgn : return numeric::sgn (arg); |
| case e_erf : return numeric::erf (arg); |
| case e_erfc : return numeric::erfc (arg); |
| case e_ncdf : return numeric::ncdf (arg); |
| case e_frac : return numeric::frac (arg); |
| case e_trunc : return numeric::trunc(arg); |
| default : return std::numeric_limits<T>::quiet_NaN(); |
| } |
| } |
| |
| template <typename T> |
| inline T process_impl(const operator_type operation, const T arg0, const T arg1) |
| { |
| switch (operation) |
| { |
| case e_add : return (arg0 + arg1); |
| case e_sub : return (arg0 - arg1); |
| case e_mul : return (arg0 * arg1); |
| case e_div : return (arg0 / arg1); |
| case e_mod : return modulus<T>(arg0,arg1); |
| case e_pow : return pow<T>(arg0,arg1); |
| case e_atan2 : return atan2<T>(arg0,arg1); |
| case e_min : return std::min<T>(arg0,arg1); |
| case e_max : return std::max<T>(arg0,arg1); |
| case e_logn : return logn<T>(arg0,arg1); |
| case e_lt : return (arg0 < arg1) ? T(1) : T(0); |
| case e_lte : return (arg0 <= arg1) ? T(1) : T(0); |
| case e_eq : return std::equal_to<T>()(arg0,arg1) ? T(1) : T(0); |
| case e_ne : return std::not_equal_to<T>()(arg0,arg1) ? T(1) : T(0); |
| case e_gte : return (arg0 >= arg1) ? T(1) : T(0); |
| case e_gt : return (arg0 > arg1) ? T(1) : T(0); |
| case e_and : return and_opr<T> (arg0,arg1); |
| case e_nand : return nand_opr<T>(arg0,arg1); |
| case e_or : return or_opr<T> (arg0,arg1); |
| case e_nor : return nor_opr<T> (arg0,arg1); |
| case e_xor : return xor_opr<T> (arg0,arg1); |
| case e_xnor : return xnor_opr<T>(arg0,arg1); |
| case e_root : return root<T> (arg0,arg1); |
| case e_roundn : return roundn<T> (arg0,arg1); |
| case e_equal : return equal<T> (arg0,arg1); |
| case e_nequal : return nequal<T> (arg0,arg1); |
| case e_hypot : return hypot<T> (arg0,arg1); |
| case e_shr : return shr<T> (arg0,arg1); |
| case e_shl : return shl<T> (arg0,arg1); |
| default : return std::numeric_limits<T>::quiet_NaN(); |
| } |
| } |
| |
| template <typename T> |
| inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) |
| { |
| switch (operation) |
| { |
| case e_add : return (arg0 + arg1); |
| case e_sub : return (arg0 - arg1); |
| case e_mul : return (arg0 * arg1); |
| case e_div : return (arg0 / arg1); |
| case e_mod : return arg0 % arg1; |
| case e_pow : return pow<T>(arg0,arg1); |
| case e_min : return std::min<T>(arg0,arg1); |
| case e_max : return std::max<T>(arg0,arg1); |
| case e_logn : return logn<T>(arg0,arg1); |
| case e_lt : return (arg0 < arg1) ? T(1) : T(0); |
| case e_lte : return (arg0 <= arg1) ? T(1) : T(0); |
| case e_eq : return (arg0 == arg1) ? T(1) : T(0); |
| case e_ne : return (arg0 != arg1) ? T(1) : T(0); |
| case e_gte : return (arg0 >= arg1) ? T(1) : T(0); |
| case e_gt : return (arg0 > arg1) ? T(1) : T(0); |
| case e_and : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); |
| 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; |
| case e_xnor : return !(arg0 ^ arg1); |
| case e_root : return root<T>(arg0,arg1); |
| case e_equal : return arg0 == arg1; |
| case e_nequal : return arg0 != arg1; |
| case e_hypot : return hypot<T>(arg0,arg1); |
| case e_shr : return arg0 >> arg1; |
| case e_shl : return arg0 << arg1; |
| default : return std::numeric_limits<T>::quiet_NaN(); |
| } |
| } |
| } |
| |
| template <typename T> |
| inline T process(const operator_type operation, const T arg) |
| { |
| return exprtk::details::numeric::details::process_impl(operation,arg); |
| } |
| |
| template <typename T> |
| inline T process(const operator_type operation, const T arg0, const T arg1) |
| { |
| return exprtk::details::numeric::details::process_impl(operation,arg0,arg1); |
| } |
| } |
| |
| template <typename T> |
| class expression_node |
| { |
| public: |
| |
| enum node_type |
| { |
| e_none , e_null , e_constant , e_unary , |
| e_binary , e_binary_ext , e_trinary , e_quaternary , |
| e_vararg , e_conditional , e_while , e_repeat , |
| e_for , e_switch , e_mswitch , e_return , |
| e_retenv , e_variable , e_stringvar , e_stringconst , |
| e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , |
| e_stringvarsize, e_strswap , e_stringsize , e_function , |
| e_vafunction , e_genfunction , e_strfunction , e_strcondition , |
| e_strccondition, 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_xnor , e_in , |
| e_like , e_ilike , e_inranges , e_ipow , |
| e_ipowinv , e_abs , e_acos , e_acosh , |
| e_asin , e_asinh , e_atan , e_atanh , |
| e_ceil , e_cos , e_cosh , e_exp , |
| e_expm1 , e_floor , e_log , e_log10 , |
| e_log2 , e_log1p , e_neg , e_pos , |
| e_round , e_sin , e_sinc , e_sinh , |
| e_sqrt , e_tan , e_tanh , e_cot , |
| e_sec , e_csc , e_r2d , e_d2r , |
| e_d2g , e_g2d , e_notl , e_sgn , |
| e_erf , e_erfc , e_ncdf , e_frac , |
| e_trunc , e_uvouv , e_vov , e_cov , |
| e_voc , e_vob , e_bov , e_cob , |
| e_boc , e_vovov , e_vovoc , e_vocov , |
| e_covov , e_covoc , e_vovovov , e_vovovoc , |
| e_vovocov , e_vocovov , e_covovov , e_covocov , |
| e_vocovoc , e_covovoc , e_vococov , e_sf3ext , |
| e_sf4ext , e_nulleq , e_strass , e_vector , |
| e_vecelem , e_rbvecelem , e_rbveccelem , e_vecdefass , |
| e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , |
| e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , |
| e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , |
| e_vecunaryop , e_break , e_continue , e_swap |
| }; |
| |
| typedef T value_type; |
| typedef expression_node<T>* expression_ptr; |
| |
| virtual ~expression_node() |
| {} |
| |
| inline virtual T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline virtual expression_node<T>* branch(const std::size_t& index = 0) const |
| { |
| return reinterpret_cast<expression_ptr>(index * 0); |
| } |
| |
| inline virtual node_type type() const |
| { |
| return e_none; |
| } |
| }; |
| |
| template <typename T> |
| inline bool is_generally_string_node(const expression_node<T>* node); |
| |
| inline bool is_true(const double v) |
| { |
| return std::not_equal_to<double>()(0.0,v); |
| } |
| |
| inline bool is_true(const long double v) |
| { |
| return std::not_equal_to<long double>()(0.0L,v); |
| } |
| |
| inline bool is_true(const float v) |
| { |
| return std::not_equal_to<float>()(0.0f,v); |
| } |
| |
| template <typename T> |
| inline bool is_true(const std::complex<T>& v) |
| { |
| return std::not_equal_to<std::complex<T> >()(std::complex<T>(0),v); |
| } |
| |
| template <typename T> |
| inline bool is_true(const expression_node<T>* node) |
| { |
| return std::not_equal_to<T>()(T(0),node->value()); |
| } |
| |
| template <typename T> |
| inline bool is_false(const expression_node<T>* node) |
| { |
| return std::equal_to<T>()(T(0),node->value()); |
| } |
| |
| template <typename T> |
| inline bool is_unary_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_unary == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_neg_unary_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_neg == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_binary_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_binary == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_variable_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_variable == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_ivariable_node(const expression_node<T>* node) |
| { |
| return node && |
| ( |
| details::expression_node<T>::e_variable == node->type() || |
| details::expression_node<T>::e_vecelem == node->type() || |
| details::expression_node<T>::e_rbvecelem == node->type() || |
| details::expression_node<T>::e_rbveccelem == node->type() |
| ); |
| } |
| |
| template <typename T> |
| inline bool is_vector_elem_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_vecelem == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_rebasevector_elem_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_rbvecelem == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_rebasevector_celem_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_rbveccelem == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_vector_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_vector == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_ivector_node(const expression_node<T>* node) |
| { |
| if (node) |
| { |
| switch (node->type()) |
| { |
| case details::expression_node<T>::e_vector : |
| case details::expression_node<T>::e_vecvalass : |
| case details::expression_node<T>::e_vecvecass : |
| case details::expression_node<T>::e_vecopvalass : |
| case details::expression_node<T>::e_vecopvecass : |
| case details::expression_node<T>::e_vecvecswap : |
| case details::expression_node<T>::e_vecvecarith : |
| case details::expression_node<T>::e_vecvalarith : |
| case details::expression_node<T>::e_valvecarith : |
| case details::expression_node<T>::e_vecunaryop : return true; |
| default : return false; |
| } |
| } |
| else |
| return false; |
| } |
| |
| template <typename T> |
| inline bool is_constant_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_constant == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_null_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_null == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_break_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_break == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_continue_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_continue == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_swap_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_swap == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_function(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_function == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_return_node(const expression_node<T>* node) |
| { |
| return node && (details::expression_node<T>::e_return == node->type()); |
| } |
| |
| template <typename T> class unary_node; |
| |
| template <typename T> |
| inline bool is_negate_node(const expression_node<T>* node) |
| { |
| if (node && is_unary_node(node)) |
| { |
| return (details::e_neg == static_cast<const unary_node<T>*>(node)->operation()); |
| } |
| else |
| return false; |
| } |
| |
| template <typename T> |
| inline bool branch_deletable(expression_node<T>* node) |
| { |
| return !is_variable_node(node) && |
| !is_string_node (node) ; |
| } |
| |
| template <std::size_t N, typename T> |
| inline bool all_nodes_valid(expression_node<T>* (&b)[N]) |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| if (0 == b[i]) return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename T, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| inline bool all_nodes_valid(const Sequence<expression_node<T>*,Allocator>& b) |
| { |
| for (std::size_t i = 0; i < b.size(); ++i) |
| { |
| if (0 == b[i]) return false; |
| } |
| |
| return true; |
| } |
| |
| template <std::size_t N, typename T> |
| inline bool all_nodes_variables(expression_node<T>* (&b)[N]) |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| if (0 == b[i]) |
| return false; |
| else if (!is_variable_node(b[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename T, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| inline bool all_nodes_variables(Sequence<expression_node<T>*,Allocator>& b) |
| { |
| for (std::size_t i = 0; i < b.size(); ++i) |
| { |
| if (0 == b[i]) |
| return false; |
| else if (!is_variable_node(b[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename NodeAllocator, typename T, std::size_t N> |
| inline void free_all_nodes(NodeAllocator& node_allocator, expression_node<T>* (&b)[N]) |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| free_node(node_allocator,b[i]); |
| } |
| } |
| |
| template <typename NodeAllocator, |
| typename T, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| inline void free_all_nodes(NodeAllocator& node_allocator, Sequence<expression_node<T>*,Allocator>& b) |
| { |
| for (std::size_t i = 0; i < b.size(); ++i) |
| { |
| free_node(node_allocator,b[i]); |
| } |
| |
| b.clear(); |
| } |
| |
| template <typename NodeAllocator, typename T> |
| inline void free_node(NodeAllocator& node_allocator, expression_node<T>*& node, const bool force_delete = false) |
| { |
| if (0 != node) |
| { |
| if ( |
| (is_variable_node(node) || is_string_node(node)) || |
| force_delete |
| ) |
| return; |
| |
| node_allocator.free(node); |
| node = 0; |
| } |
| } |
| |
| template <typename Type> |
| class vector_holder |
| { |
| private: |
| |
| typedef Type value_type; |
| typedef value_type* value_ptr; |
| typedef const value_ptr const_value_ptr; |
| |
| class vector_holder_base |
| { |
| public: |
| |
| virtual ~vector_holder_base(){} |
| |
| inline value_ptr operator[](const std::size_t& index) const |
| { |
| return value_at(index); |
| } |
| |
| inline std::size_t size() const |
| { |
| return vector_size(); |
| } |
| |
| inline value_ptr data() const |
| { |
| return value_at(0); |
| } |
| |
| virtual inline bool rebaseable() const |
| { |
| return false; |
| } |
| |
| virtual void set_ref(value_ptr*) {} |
| |
| protected: |
| |
| virtual value_ptr value_at(const std::size_t&) const = 0; |
| virtual std::size_t vector_size() const = 0; |
| }; |
| |
| class array_vector_impl : public vector_holder_base |
| { |
| public: |
| |
| array_vector_impl(const Type* vec, const std::size_t& vec_size) |
| : vec_(vec), |
| size_(vec_size) |
| {} |
| |
| protected: |
| |
| value_ptr value_at(const std::size_t& index) const |
| { |
| if (index < size_) |
| return const_cast<const_value_ptr>(vec_ + index); |
| else |
| return const_value_ptr(0); |
| } |
| |
| std::size_t vector_size() const |
| { |
| return size_; |
| } |
| |
| private: |
| |
| array_vector_impl operator=(const array_vector_impl&); |
| |
| const Type* vec_; |
| const std::size_t size_; |
| }; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| class sequence_vector_impl : public vector_holder_base |
| { |
| public: |
| |
| typedef Sequence<Type,Allocator> sequence_t; |
| |
| sequence_vector_impl(sequence_t& seq) |
| : sequence_(seq) |
| {} |
| |
| protected: |
| |
| value_ptr value_at(const std::size_t& index) const |
| { |
| return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); |
| } |
| |
| std::size_t vector_size() const |
| { |
| return sequence_.size(); |
| } |
| |
| private: |
| |
| sequence_vector_impl operator=(const sequence_vector_impl&); |
| |
| sequence_t& sequence_; |
| }; |
| |
| class vector_view_impl : public vector_holder_base |
| { |
| public: |
| |
| typedef exprtk::vector_view<Type> vector_view_t; |
| |
| vector_view_impl(vector_view_t& vec_view) |
| : vec_view_(vec_view) |
| {} |
| |
| void set_ref(value_ptr* ref) |
| { |
| vec_view_.set_ref(ref); |
| } |
| |
| virtual inline bool rebaseable() const |
| { |
| return true; |
| } |
| |
| protected: |
| |
| value_ptr value_at(const std::size_t& index) const |
| { |
| return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); |
| } |
| |
| std::size_t vector_size() const |
| { |
| return vec_view_.size(); |
| } |
| |
| private: |
| |
| vector_view_impl operator=(const vector_view_impl&); |
| |
| vector_view_t& vec_view_; |
| }; |
| |
| public: |
| |
| typedef typename details::vec_data_store<Type> vds_t; |
| |
| vector_holder(Type* vec, const std::size_t& vec_size) |
| : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) |
| {} |
| |
| vector_holder(const vds_t& vds) |
| : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) |
| {} |
| |
| template <typename Allocator> |
| vector_holder(std::vector<Type,Allocator>& vec) |
| : vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::vector>(vec)) |
| {} |
| |
| vector_holder(exprtk::vector_view<Type>& vec) |
| : vector_holder_base_(new(buffer)vector_view_impl(vec)) |
| {} |
| |
| inline value_ptr operator[](const std::size_t& index) const |
| { |
| return (*vector_holder_base_)[index]; |
| } |
| |
| inline std::size_t size() const |
| { |
| return vector_holder_base_->size(); |
| } |
| |
| inline value_ptr data() const |
| { |
| return vector_holder_base_->data(); |
| } |
| |
| void set_ref(value_ptr* ref) |
| { |
| return vector_holder_base_->set_ref(ref); |
| } |
| |
| bool rebaseable() const |
| { |
| return vector_holder_base_->rebaseable(); |
| } |
| |
| private: |
| |
| mutable vector_holder_base* vector_holder_base_; |
| uchar_t buffer[64]; |
| }; |
| |
| template <typename T> |
| class null_node : public expression_node<T> |
| { |
| public: |
| |
| inline T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_null; |
| } |
| }; |
| |
| template <typename T> |
| class null_eq_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| null_eq_node(expression_ptr brnch, const bool equality = true) |
| : branch_(brnch), |
| branch_deletable_(branch_deletable(branch_)), |
| equality_(equality) |
| {} |
| |
| ~null_eq_node() |
| { |
| if (branch_ && branch_deletable_) |
| { |
| delete branch_; |
| branch_ = 0; |
| } |
| } |
| |
| inline T value() const |
| { |
| const T v = branch_->value(); |
| const bool result = details::numeric::is_nan(v); |
| |
| if (result) |
| return (equality_) ? T(1) : T(0); |
| else |
| return (equality_) ? T(0) : T(1); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_nulleq; |
| } |
| |
| inline operator_type operation() const |
| { |
| return details::e_eq; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_; |
| } |
| |
| private: |
| |
| expression_ptr branch_; |
| bool branch_deletable_; |
| bool equality_; |
| }; |
| |
| template <typename T> |
| class literal_node : public expression_node<T> |
| { |
| public: |
| |
| explicit literal_node(const T& v) |
| : value_(v) |
| {} |
| |
| inline T value() const |
| { |
| return value_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_constant; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return reinterpret_cast<expression_node<T>*>(0); |
| } |
| |
| private: |
| |
| literal_node(literal_node<T>&) {} |
| literal_node<T>& operator=(literal_node<T>&) { return *this; } |
| |
| const T value_; |
| }; |
| |
| template <typename T> |
| struct range_pack; |
| |
| template <typename T> |
| struct range_data_type; |
| |
| template <typename T> |
| class range_interface |
| { |
| public: |
| |
| typedef range_pack<T> range_t; |
| |
| virtual ~range_interface() |
| {} |
| |
| virtual range_t& range_ref() = 0; |
| |
| virtual const range_t& range_ref() const = 0; |
| }; |
| |
| template <typename T> |
| class string_base_node |
| { |
| public: |
| |
| typedef range_data_type<T> range_data_type_t; |
| |
| virtual ~string_base_node() |
| {} |
| |
| virtual std::string str () const = 0; |
| |
| virtual const char* base() const = 0; |
| |
| virtual std::size_t size() const = 0; |
| }; |
| |
| template <typename T> |
| class string_literal_node : public expression_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef range_pack<T> range_t; |
| |
| explicit string_literal_node(const std::string& v) |
| : value_(v) |
| { |
| rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1); |
| rp_.cache.first = rp_.n0_c.second; |
| rp_.cache.second = rp_.n1_c.second; |
| } |
| |
| inline T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_stringconst; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return reinterpret_cast<expression_node<T>*>(0); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return value_.data(); |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return rp_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return rp_; |
| } |
| |
| private: |
| |
| string_literal_node(const string_literal_node<T>&); |
| string_literal_node<T>& operator=(const string_literal_node<T>&); |
| |
| const std::string value_; |
| range_t rp_; |
| }; |
| |
| template <typename T> |
| class unary_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| unary_node(const operator_type& opr, |
| expression_ptr brnch) |
| : operation_(opr), |
| branch_(brnch), |
| branch_deletable_(branch_deletable(branch_)) |
| {} |
| |
| ~unary_node() |
| { |
| if (branch_ && branch_deletable_) |
| { |
| delete branch_; |
| branch_ = 0; |
| } |
| } |
| |
| inline T value() const |
| { |
| const T arg = branch_->value(); |
| return numeric::process<T>(operation_,arg); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_unary; |
| } |
| |
| inline operator_type operation() const |
| { |
| return operation_; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_; |
| } |
| |
| inline void release() |
| { |
| branch_deletable_ = false; |
| } |
| |
| protected: |
| |
| operator_type operation_; |
| expression_ptr branch_; |
| bool branch_deletable_; |
| }; |
| |
| template <typename T, std::size_t D, bool B> |
| struct construct_branch_pair |
| { |
| template <std::size_t N> |
| static inline void process(std::pair<expression_node<T>*,bool> (&)[N], expression_node<T>*) |
| {} |
| }; |
| |
| template <typename T, std::size_t D> |
| struct construct_branch_pair<T,D,true> |
| { |
| template <std::size_t N> |
| static inline void process(std::pair<expression_node<T>*,bool> (&branch)[N], expression_node<T>* b) |
| { |
| if (b) |
| { |
| branch[D] = std::make_pair(b,branch_deletable(b)); |
| } |
| } |
| }; |
| |
| template <std::size_t N, typename T> |
| inline void init_branches(std::pair<expression_node<T>*,bool> (&branch)[N], |
| expression_node<T>* b0, |
| expression_node<T>* b1 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b2 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b3 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b4 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b5 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b6 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b7 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b8 = reinterpret_cast<expression_node<T>*>(0), |
| expression_node<T>* b9 = reinterpret_cast<expression_node<T>*>(0)) |
| { |
| construct_branch_pair<T,0,(N > 0)>::process(branch,b0); |
| construct_branch_pair<T,1,(N > 1)>::process(branch,b1); |
| construct_branch_pair<T,2,(N > 2)>::process(branch,b2); |
| construct_branch_pair<T,3,(N > 3)>::process(branch,b3); |
| construct_branch_pair<T,4,(N > 4)>::process(branch,b4); |
| construct_branch_pair<T,5,(N > 5)>::process(branch,b5); |
| construct_branch_pair<T,6,(N > 6)>::process(branch,b6); |
| construct_branch_pair<T,7,(N > 7)>::process(branch,b7); |
| construct_branch_pair<T,8,(N > 8)>::process(branch,b8); |
| construct_branch_pair<T,9,(N > 9)>::process(branch,b9); |
| } |
| |
| struct cleanup_branches |
| { |
| template <typename T, std::size_t N> |
| static inline void execute(std::pair<expression_node<T>*,bool> (&branch)[N]) |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| if (branch[i].first && branch[i].second) |
| { |
| delete branch[i].first; |
| branch[i].first = 0; |
| } |
| } |
| } |
| |
| template <typename T, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline void execute(Sequence<std::pair<expression_node<T>*,bool>,Allocator>& branch) |
| { |
| for (std::size_t i = 0; i < branch.size(); ++i) |
| { |
| if (branch[i].first && branch[i].second) |
| { |
| delete branch[i].first; |
| branch[i].first = 0; |
| } |
| } |
| } |
| }; |
| |
| template <typename T> |
| class binary_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| |
| binary_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : operation_(opr) |
| { |
| init_branches<2>(branch_,branch0,branch1); |
| } |
| |
| ~binary_node() |
| { |
| cleanup_branches::execute<T,2>(branch_); |
| } |
| |
| inline T value() const |
| { |
| const T arg0 = branch_[0].first->value(); |
| const T arg1 = branch_[1].first->value(); |
| return numeric::process<T>(operation_,arg0,arg1); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_binary; |
| } |
| |
| inline operator_type operation() |
| { |
| return operation_; |
| } |
| |
| inline expression_node<T>* 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<expression_ptr>(0); |
| } |
| |
| protected: |
| |
| operator_type operation_; |
| branch_t branch_[2]; |
| }; |
| |
| template <typename T, typename Operation> |
| class binary_ext_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| |
| binary_ext_node(expression_ptr branch0, expression_ptr branch1) |
| { |
| init_branches<2>(branch_,branch0,branch1); |
| } |
| |
| ~binary_ext_node() |
| { |
| cleanup_branches::execute<T,2>(branch_); |
| } |
| |
| inline T value() const |
| { |
| const T arg0 = branch_[0].first->value(); |
| const T arg1 = branch_[1].first->value(); |
| |
| return Operation::process(arg0,arg1); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_binary_ext; |
| } |
| |
| inline operator_type operation() |
| { |
| return Operation::operation(); |
| } |
| |
| inline expression_node<T>* 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<expression_ptr>(0); |
| } |
| |
| protected: |
| |
| branch_t branch_[2]; |
| }; |
| |
| template <typename T> |
| class trinary_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| |
| trinary_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1, |
| expression_ptr branch2) |
| : operation_(opr) |
| { |
| init_branches<3>(branch_,branch0,branch1,branch2); |
| } |
| |
| ~trinary_node() |
| { |
| cleanup_branches::execute<T,3>(branch_); |
| } |
| |
| inline T value() const |
| { |
| const T arg0 = branch_[0].first->value(); |
| const T arg1 = branch_[1].first->value(); |
| const T arg2 = branch_[2].first->value(); |
| |
| switch (operation_) |
| { |
| case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); |
| |
| case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); |
| |
| case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) |
| return arg1; |
| else |
| return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); |
| |
| default : { |
| exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| } |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_trinary; |
| } |
| |
| protected: |
| |
| operator_type operation_; |
| branch_t branch_[3]; |
| }; |
| |
| template <typename T> |
| class quaternary_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| |
| quaternary_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1, |
| expression_ptr branch2, |
| expression_ptr branch3) |
| : operation_(opr) |
| { |
| init_branches<4>(branch_,branch0,branch1,branch2,branch3); |
| } |
| |
| ~quaternary_node() |
| { |
| cleanup_branches::execute<T,4>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_quaternary; |
| } |
| |
| protected: |
| |
| operator_type operation_; |
| branch_t branch_[4]; |
| }; |
| |
| template <typename T> |
| class conditional_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| conditional_node(expression_ptr test, |
| expression_ptr consequent, |
| expression_ptr alternative) |
| : test_(test), |
| consequent_(consequent), |
| alternative_(alternative), |
| test_deletable_(branch_deletable(test_)), |
| consequent_deletable_(branch_deletable(consequent_)), |
| alternative_deletable_(branch_deletable(alternative_)) |
| {} |
| |
| ~conditional_node() |
| { |
| if (test_ && test_deletable_ ) delete test_; |
| if (consequent_ && consequent_deletable_ ) delete consequent_; |
| if (alternative_ && alternative_deletable_) delete alternative_; |
| } |
| |
| inline T value() const |
| { |
| if (is_true(test_)) |
| return consequent_->value(); |
| else |
| return alternative_->value(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_conditional; |
| } |
| |
| private: |
| |
| expression_ptr test_; |
| expression_ptr consequent_; |
| expression_ptr alternative_; |
| bool test_deletable_; |
| bool consequent_deletable_; |
| bool alternative_deletable_; |
| }; |
| |
| template <typename T> |
| class cons_conditional_node : public expression_node<T> |
| { |
| public: |
| |
| // Consequent only conditional statement node |
| typedef expression_node<T>* expression_ptr; |
| |
| cons_conditional_node(expression_ptr test, |
| expression_ptr consequent) |
| : test_(test), |
| consequent_(consequent), |
| test_deletable_(branch_deletable(test_)), |
| consequent_deletable_(branch_deletable(consequent_)) |
| {} |
| |
| ~cons_conditional_node() |
| { |
| if (test_ && test_deletable_ ) delete test_; |
| if (consequent_ && consequent_deletable_) delete consequent_; |
| } |
| |
| inline T value() const |
| { |
| if (is_true(test_)) |
| return consequent_->value(); |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_conditional; |
| } |
| |
| private: |
| |
| expression_ptr test_; |
| expression_ptr consequent_; |
| bool test_deletable_; |
| bool consequent_deletable_; |
| }; |
| |
| #ifndef exprtk_disable_break_continue |
| template <typename T> |
| class break_exception |
| { |
| public: |
| |
| break_exception(const T& v) |
| : value(v) |
| {} |
| |
| T value; |
| }; |
| |
| class continue_exception |
| {}; |
| |
| template <typename T> |
| class break_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| break_node(expression_ptr ret = expression_ptr(0)) |
| : return_(ret), |
| return_deletable_(branch_deletable(return_)) |
| {} |
| |
| ~break_node() |
| { |
| if (return_deletable_) |
| { |
| delete return_; |
| } |
| } |
| |
| inline T value() const |
| { |
| throw break_exception<T>(return_ ? return_->value() : std::numeric_limits<T>::quiet_NaN()); |
| #ifndef _MSC_VER |
| return std::numeric_limits<T>::quiet_NaN(); |
| #endif |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_break; |
| } |
| |
| private: |
| |
| expression_ptr return_; |
| bool return_deletable_; |
| }; |
| |
| template <typename T> |
| class continue_node : public expression_node<T> |
| { |
| public: |
| |
| inline T value() const |
| { |
| throw continue_exception(); |
| #ifndef _MSC_VER |
| return std::numeric_limits<T>::quiet_NaN(); |
| #endif |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_break; |
| } |
| }; |
| #endif |
| |
| template <typename T> |
| class while_loop_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| while_loop_node(expression_ptr condition, expression_ptr loop_body) |
| : condition_(condition), |
| loop_body_(loop_body), |
| condition_deletable_(branch_deletable(condition_)), |
| loop_body_deletable_(branch_deletable(loop_body_)) |
| {} |
| |
| ~while_loop_node() |
| { |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| while (is_true(condition_)) |
| { |
| result = loop_body_->value(); |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_while; |
| } |
| |
| private: |
| |
| expression_ptr condition_; |
| expression_ptr loop_body_; |
| bool condition_deletable_; |
| bool loop_body_deletable_; |
| }; |
| |
| template <typename T> |
| class repeat_until_loop_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| repeat_until_loop_node(expression_ptr condition, expression_ptr loop_body) |
| : condition_(condition), |
| loop_body_(loop_body), |
| condition_deletable_(branch_deletable(condition_)), |
| loop_body_deletable_(branch_deletable(loop_body_)) |
| {} |
| |
| ~repeat_until_loop_node() |
| { |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| do |
| { |
| result = loop_body_->value(); |
| } |
| while (is_false(condition_)); |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_repeat; |
| } |
| |
| private: |
| |
| expression_ptr condition_; |
| expression_ptr loop_body_; |
| bool condition_deletable_; |
| bool loop_body_deletable_; |
| }; |
| |
| template <typename T> |
| class for_loop_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| for_loop_node(expression_ptr initialiser, |
| expression_ptr condition, |
| expression_ptr incrementor, |
| expression_ptr loop_body) |
| : initialiser_(initialiser), |
| condition_ (condition), |
| incrementor_(incrementor), |
| loop_body_ (loop_body), |
| initialiser_deletable_(branch_deletable(initialiser_)), |
| condition_deletable_ (branch_deletable(condition_ )), |
| incrementor_deletable_(branch_deletable(incrementor_)), |
| loop_body_deletable_ (branch_deletable(loop_body_ )) |
| {} |
| |
| ~for_loop_node() |
| { |
| if (initialiser_ && initialiser_deletable_) |
| { |
| delete initialiser_; |
| } |
| |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (incrementor_ && incrementor_deletable_) |
| { |
| delete incrementor_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| if (initialiser_) |
| initialiser_->value(); |
| |
| if (incrementor_) |
| { |
| while (is_true(condition_)) |
| { |
| result = loop_body_->value(); |
| incrementor_->value(); |
| } |
| } |
| else |
| { |
| while (is_true(condition_)) |
| { |
| result = loop_body_->value(); |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_for; |
| } |
| |
| private: |
| |
| expression_ptr initialiser_; |
| expression_ptr condition_ ; |
| expression_ptr incrementor_; |
| expression_ptr loop_body_ ; |
| bool initialiser_deletable_; |
| bool condition_deletable_ ; |
| bool incrementor_deletable_; |
| bool loop_body_deletable_ ; |
| }; |
| |
| #ifndef exprtk_disable_break_continue |
| template <typename T> |
| class while_loop_bc_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| while_loop_bc_node(expression_ptr condition, expression_ptr loop_body) |
| : condition_(condition), |
| loop_body_(loop_body), |
| condition_deletable_(branch_deletable(condition_)), |
| loop_body_deletable_(branch_deletable(loop_body_)) |
| {} |
| |
| ~while_loop_bc_node() |
| { |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| while (is_true(condition_)) |
| { |
| try |
| { |
| result = loop_body_->value(); |
| } |
| catch(const break_exception<T>& e) |
| { |
| return e.value; |
| } |
| catch(const continue_exception&) |
| {} |
| } |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_while; |
| } |
| |
| private: |
| |
| expression_ptr condition_; |
| expression_ptr loop_body_; |
| bool condition_deletable_; |
| bool loop_body_deletable_; |
| }; |
| |
| template <typename T> |
| class repeat_until_loop_bc_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body) |
| : condition_(condition), |
| loop_body_(loop_body), |
| condition_deletable_(branch_deletable(condition_)), |
| loop_body_deletable_(branch_deletable(loop_body_)) |
| {} |
| |
| ~repeat_until_loop_bc_node() |
| { |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| do |
| { |
| try |
| { |
| result = loop_body_->value(); |
| } |
| catch(const break_exception<T>& e) |
| { |
| return e.value; |
| } |
| catch(const continue_exception&) |
| {} |
| } |
| while (is_false(condition_)); |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_repeat; |
| } |
| |
| private: |
| |
| expression_ptr condition_; |
| expression_ptr loop_body_; |
| bool condition_deletable_; |
| bool loop_body_deletable_; |
| }; |
| |
| template <typename T> |
| class for_loop_bc_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| for_loop_bc_node(expression_ptr initialiser, |
| expression_ptr condition, |
| expression_ptr incrementor, |
| expression_ptr loop_body) |
| : initialiser_(initialiser), |
| condition_ (condition ), |
| incrementor_(incrementor), |
| loop_body_ (loop_body ), |
| initialiser_deletable_(branch_deletable(initialiser_)), |
| condition_deletable_ (branch_deletable(condition_ )), |
| incrementor_deletable_(branch_deletable(incrementor_)), |
| loop_body_deletable_ (branch_deletable(loop_body_ )) |
| {} |
| |
| ~for_loop_bc_node() |
| { |
| if (initialiser_ && initialiser_deletable_) |
| { |
| delete initialiser_; |
| } |
| |
| if (condition_ && condition_deletable_) |
| { |
| delete condition_; |
| } |
| |
| if (incrementor_ && incrementor_deletable_) |
| { |
| delete incrementor_; |
| } |
| |
| if (loop_body_ && loop_body_deletable_) |
| { |
| delete loop_body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| if (initialiser_) |
| initialiser_->value(); |
| |
| if (incrementor_) |
| { |
| while (is_true(condition_)) |
| { |
| try |
| { |
| result = loop_body_->value(); |
| } |
| catch(const break_exception<T>& e) |
| { |
| return e.value; |
| } |
| catch(const continue_exception&) |
| {} |
| |
| incrementor_->value(); |
| } |
| } |
| else |
| { |
| while (is_true(condition_)) |
| { |
| try |
| { |
| result = loop_body_->value(); |
| } |
| catch(const break_exception<T>& e) |
| { |
| return e.value; |
| } |
| catch(const continue_exception&) |
| {} |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_for; |
| } |
| |
| private: |
| |
| expression_ptr initialiser_; |
| expression_ptr condition_ ; |
| expression_ptr incrementor_; |
| expression_ptr loop_body_ ; |
| bool initialiser_deletable_; |
| bool condition_deletable_ ; |
| bool incrementor_deletable_; |
| bool loop_body_deletable_ ; |
| }; |
| #endif |
| |
| template <typename T> |
| class switch_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| switch_node(const Sequence<expression_ptr,Allocator>& arg_list) |
| { |
| if (1 != (arg_list.size() & 1)) |
| return; |
| |
| arg_list_.resize(arg_list.size()); |
| delete_branch_.resize(arg_list.size()); |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (arg_list[i]) |
| { |
| arg_list_[i] = arg_list[i]; |
| delete_branch_[i] = static_cast<unsigned char>(branch_deletable(arg_list_[i]) ? 1 : 0); |
| } |
| else |
| { |
| arg_list_.clear(); |
| delete_branch_.clear(); |
| return; |
| } |
| } |
| } |
| |
| ~switch_node() |
| { |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| if (arg_list_[i] && delete_branch_[i]) |
| { |
| delete arg_list_[i]; |
| arg_list_[i] = 0; |
| } |
| } |
| } |
| |
| inline T value() const |
| { |
| if (!arg_list_.empty()) |
| { |
| const std::size_t upper_bound = (arg_list_.size() - 1); |
| |
| for (std::size_t i = 0; i < upper_bound; i += 2) |
| { |
| expression_ptr condition = arg_list_[i ]; |
| expression_ptr consequent = arg_list_[i + 1]; |
| |
| if (is_true(condition)) |
| { |
| return consequent->value(); |
| } |
| } |
| |
| return arg_list_[upper_bound]->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_switch; |
| } |
| |
| protected: |
| |
| std::vector<expression_ptr> arg_list_; |
| std::vector<unsigned char> delete_branch_; |
| }; |
| |
| template <typename T, typename Switch_N> |
| class switch_n_node : public switch_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| switch_n_node(const Sequence<expression_ptr,Allocator>& arg_list) |
| : switch_node<T>(arg_list) |
| {} |
| |
| inline T value() const |
| { |
| return Switch_N::process(switch_node<T>::arg_list_); |
| } |
| }; |
| |
| template <typename T> |
| class multi_switch_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| multi_switch_node(const Sequence<expression_ptr,Allocator>& arg_list) |
| { |
| if (0 != (arg_list.size() & 1)) |
| return; |
| |
| arg_list_.resize(arg_list.size()); |
| delete_branch_.resize(arg_list.size()); |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (arg_list[i]) |
| { |
| arg_list_[i] = arg_list[i]; |
| delete_branch_[i] = static_cast<unsigned char>(branch_deletable(arg_list_[i]) ? 1 : 0); |
| } |
| else |
| { |
| arg_list_.clear(); |
| delete_branch_.clear(); |
| return; |
| } |
| } |
| } |
| |
| ~multi_switch_node() |
| { |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| if (arg_list_[i] && delete_branch_[i]) |
| { |
| delete arg_list_[i]; |
| arg_list_[i] = 0; |
| } |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = T(0); |
| |
| if (arg_list_.empty()) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| const std::size_t upper_bound = (arg_list_.size() - 1); |
| |
| for (std::size_t i = 0; i < upper_bound; i += 2) |
| { |
| expression_ptr condition = arg_list_[i ]; |
| expression_ptr consequent = arg_list_[i + 1]; |
| |
| if (is_true(condition)) |
| { |
| result = consequent->value(); |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_mswitch; |
| } |
| |
| private: |
| |
| std::vector<expression_ptr> arg_list_; |
| std::vector<unsigned char> delete_branch_; |
| }; |
| |
| template <typename T> |
| class ivariable |
| { |
| public: |
| |
| virtual ~ivariable() |
| {} |
| |
| virtual T& ref() = 0; |
| virtual const T& ref() const = 0; |
| }; |
| |
| template <typename T> |
| class variable_node : public expression_node<T>, |
| public ivariable <T> |
| { |
| public: |
| |
| static T null_value; |
| |
| explicit variable_node() |
| : value_(&null_value), |
| delete_value_(false) |
| {} |
| |
| variable_node(T& v) |
| : value_(&v), |
| delete_value_(false) |
| {} |
| |
| ~variable_node() |
| { |
| if (delete_value_) |
| { |
| delete value_; |
| } |
| } |
| |
| inline bool operator <(const variable_node<T>& v) const |
| { |
| return this < (&v); |
| } |
| |
| inline T value() const |
| { |
| return (*value_); |
| } |
| |
| inline T& ref() |
| { |
| return (*value_); |
| } |
| |
| inline const T& ref() const |
| { |
| return (*value_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_variable; |
| } |
| |
| inline bool& delete_value() |
| { |
| return delete_value_; |
| } |
| |
| private: |
| |
| T* value_; |
| bool delete_value_; |
| }; |
| |
| template <typename T> |
| T variable_node<T>::null_value = T(std::numeric_limits<T>::quiet_NaN()); |
| |
| template <typename T> |
| struct range_pack |
| { |
| typedef expression_node<T>* expression_node_ptr; |
| typedef std::pair<std::size_t,std::size_t> cached_range_t; |
| |
| range_pack() |
| : n0_e (std::make_pair(false,expression_node_ptr(0))), |
| n1_e (std::make_pair(false,expression_node_ptr(0))), |
| n0_c (std::make_pair(false,0)), |
| n1_c (std::make_pair(false,0)), |
| cache(std::make_pair(0,0)) |
| {} |
| |
| void clear() |
| { |
| n0_e = std::make_pair(false,expression_node_ptr(0)); |
| n1_e = std::make_pair(false,expression_node_ptr(0)); |
| n0_c = std::make_pair(false,0); |
| n1_c = std::make_pair(false,0); |
| cache = std::make_pair(0,0); |
| } |
| |
| void free() |
| { |
| if (n0_e.first && n0_e.second) |
| { |
| n0_e.first = false; |
| |
| if ( |
| !is_variable_node(n0_e.second) && |
| !is_string_node (n0_e.second) |
| ) |
| { |
| delete n0_e.second; |
| n0_e.second = expression_node_ptr(0); |
| } |
| } |
| |
| if (n1_e.first && n1_e.second) |
| { |
| n1_e.first = false; |
| |
| if ( |
| !is_variable_node(n1_e.second) && |
| !is_string_node (n1_e.second) |
| ) |
| { |
| delete n1_e.second; |
| n1_e.second = expression_node_ptr(0); |
| } |
| } |
| } |
| |
| bool const_range() |
| { |
| return ( n0_c.first && n1_c.first) && |
| (!n0_e.first && !n1_e.first); |
| } |
| |
| bool var_range() |
| { |
| return ( n0_e.first && n1_e.first) && |
| (!n0_c.first && !n1_c.first); |
| } |
| |
| bool operator()(std::size_t& r0, std::size_t& r1, const std::size_t& size = std::numeric_limits<std::size_t>::max()) const |
| { |
| if (n0_c.first) |
| r0 = n0_c.second; |
| else if (n0_e.first) |
| { |
| T r0_value = n0_e.second->value(); |
| |
| if (r0_value < 0) |
| return false; |
| else |
| r0 = static_cast<std::size_t>(details::numeric::to_int64(r0_value)); |
| } |
| else |
| return false; |
| |
| if (n1_c.first) |
| r1 = n1_c.second; |
| else if (n1_e.first) |
| { |
| T r1_value = n1_e.second->value(); |
| |
| if (r1_value < 0) |
| return false; |
| else |
| r1 = static_cast<std::size_t>(details::numeric::to_int64(r1_value)); |
| } |
| else |
| return false; |
| |
| if ( |
| (std::numeric_limits<std::size_t>::max() != size) && |
| (std::numeric_limits<std::size_t>::max() == r1 ) |
| ) |
| { |
| r1 = size - 1; |
| } |
| |
| cache.first = r0; |
| cache.second = r1; |
| |
| return (r0 <= r1); |
| } |
| |
| inline std::size_t const_size() const |
| { |
| return (n1_c.second - n0_c.second + 1); |
| } |
| |
| inline std::size_t cache_size() const |
| { |
| return (cache.second - cache.first + 1); |
| } |
| |
| std::pair<bool,expression_node_ptr> n0_e; |
| std::pair<bool,expression_node_ptr> n1_e; |
| std::pair<bool,std::size_t > n0_c; |
| std::pair<bool,std::size_t > n1_c; |
| mutable cached_range_t cache; |
| }; |
| |
| template <typename T> |
| class string_base_node; |
| |
| template <typename T> |
| struct range_data_type |
| { |
| typedef range_pack<T> range_t; |
| typedef string_base_node<T>* strbase_ptr_t; |
| |
| range_data_type() |
| : range(0), |
| data (0), |
| size (0), |
| type_size(0), |
| str_node (0) |
| {} |
| |
| range_t* range; |
| void* data; |
| std::size_t size; |
| std::size_t type_size; |
| strbase_ptr_t str_node; |
| }; |
| |
| template <typename T> class vector_node; |
| |
| template <typename T> |
| class vector_interface |
| { |
| public: |
| |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| virtual ~vector_interface() |
| {} |
| |
| virtual std::size_t size () const = 0; |
| |
| virtual vector_node_ptr vec() const = 0; |
| |
| virtual vector_node_ptr vec() = 0; |
| |
| virtual vds_t& vds () = 0; |
| |
| virtual const vds_t& vds () const = 0; |
| |
| virtual bool side_effect () const { return false; } |
| }; |
| |
| template <typename T> |
| class vector_node : public expression_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_holder<T> vector_holder_t; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| vector_node(vector_holder_t* vh) |
| : vector_holder_(vh), |
| vds_((*vector_holder_).size(),(*vector_holder_)[0]) |
| { |
| vector_holder_->set_ref(&vds_.ref()); |
| } |
| |
| vector_node(const vds_t& vds, vector_holder_t* vh) |
| : vector_holder_(vh), |
| vds_(vds) |
| {} |
| |
| inline T value() const |
| { |
| return vds().data()[0]; |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return const_cast<vector_node_ptr>(this); |
| } |
| |
| vector_node_ptr vec() |
| { |
| return this; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vector; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| inline vector_holder_t& vec_holder() |
| { |
| return (*vector_holder_); |
| } |
| |
| private: |
| |
| vector_holder_t* vector_holder_; |
| vds_t vds_; |
| }; |
| |
| template <typename T> |
| class vector_elem_node : public expression_node<T>, |
| public ivariable <T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_holder<T> vector_holder_t; |
| typedef vector_holder_t* vector_holder_ptr; |
| |
| vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) |
| : index_(index), |
| vec_holder_(vec_holder), |
| vector_base_((*vec_holder)[0]), |
| index_deletable_(branch_deletable(index_)) |
| {} |
| |
| ~vector_elem_node() |
| { |
| if (index_ && index_deletable_) |
| { |
| delete index_; |
| } |
| } |
| |
| inline T value() const |
| { |
| return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline T& ref() |
| { |
| return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline const T& ref() const |
| { |
| return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecelem; |
| } |
| |
| inline vector_holder_t& vec_holder() |
| { |
| return (*vec_holder_); |
| } |
| |
| private: |
| |
| expression_ptr index_; |
| vector_holder_ptr vec_holder_; |
| T* vector_base_; |
| bool index_deletable_; |
| }; |
| |
| template <typename T> |
| class rebasevector_elem_node : public expression_node<T>, |
| public ivariable <T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_holder<T> vector_holder_t; |
| typedef vector_holder_t* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) |
| : index_(index), |
| index_deletable_(branch_deletable(index_)), |
| vector_holder_(vec_holder), |
| vds_((*vector_holder_).size(),(*vector_holder_)[0]) |
| { |
| vector_holder_->set_ref(&vds_.ref()); |
| } |
| |
| ~rebasevector_elem_node() |
| { |
| if (index_ && index_deletable_) |
| { |
| delete index_; |
| } |
| } |
| |
| inline T value() const |
| { |
| return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline T& ref() |
| { |
| return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline const T& ref() const |
| { |
| return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value()))); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_rbvecelem; |
| } |
| |
| inline vector_holder_t& vec_holder() |
| { |
| return (*vector_holder_); |
| } |
| |
| private: |
| |
| expression_ptr index_; |
| bool index_deletable_; |
| vector_holder_ptr vector_holder_; |
| vds_t vds_; |
| }; |
| |
| template <typename T> |
| class rebasevector_celem_node : public expression_node<T>, |
| public ivariable <T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_holder<T> vector_holder_t; |
| typedef vector_holder_t* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) |
| : index_(index), |
| vector_holder_(vec_holder), |
| vds_((*vector_holder_).size(),(*vector_holder_)[0]) |
| { |
| vector_holder_->set_ref(&vds_.ref()); |
| } |
| |
| inline T value() const |
| { |
| return *(vds_.data() + index_); |
| } |
| |
| inline T& ref() |
| { |
| return *(vds_.data() + index_); |
| } |
| |
| inline const T& ref() const |
| { |
| return *(vds_.data() + index_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_rbveccelem; |
| } |
| |
| inline vector_holder_t& vec_holder() |
| { |
| return (*vector_holder_); |
| } |
| |
| private: |
| |
| std::size_t index_; |
| vector_holder_ptr vector_holder_; |
| vds_t vds_; |
| }; |
| |
| template <typename T> |
| class vector_assignment_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| vector_assignment_node(T* vector_base, |
| const std::size_t& size, |
| const std::vector<expression_ptr>& initialiser_list, |
| const bool single_value_initialse) |
| : vector_base_(vector_base), |
| initialiser_list_(initialiser_list), |
| size_(size), |
| single_value_initialse_(single_value_initialse) |
| {} |
| |
| ~vector_assignment_node() |
| { |
| for (std::size_t i = 0; i < initialiser_list_.size(); ++i) |
| { |
| if (branch_deletable(initialiser_list_[i])) |
| { |
| delete initialiser_list_[i]; |
| } |
| } |
| } |
| |
| inline T value() const |
| { |
| if (single_value_initialse_) |
| { |
| for (std::size_t i = 0; i < size_; ++i) |
| { |
| *(vector_base_ + i) = initialiser_list_[0]->value(); |
| } |
| } |
| else |
| { |
| std::size_t il_size = initialiser_list_.size(); |
| |
| for (std::size_t i = 0; i < il_size; ++i) |
| { |
| *(vector_base_ + i) = initialiser_list_[i]->value(); |
| } |
| |
| if (il_size < size_) |
| { |
| for (std::size_t i = il_size; i < size_; ++i) |
| { |
| *(vector_base_ + i) = T(0); |
| } |
| } |
| } |
| |
| return *(vector_base_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecdefass; |
| } |
| |
| private: |
| |
| vector_assignment_node<T>& operator=(const vector_assignment_node<T>&); |
| |
| mutable T* vector_base_; |
| std::vector<expression_ptr> initialiser_list_; |
| const std::size_t size_; |
| const bool single_value_initialse_; |
| }; |
| |
| template <typename T> |
| class swap_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef variable_node<T>* variable_node_ptr; |
| |
| swap_node(variable_node_ptr var0, variable_node_ptr var1) |
| : var0_(var0), |
| var1_(var1) |
| {} |
| |
| inline T value() const |
| { |
| std::swap(var0_->ref(),var1_->ref()); |
| return var1_->ref(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_swap; |
| } |
| |
| private: |
| |
| variable_node_ptr var0_; |
| variable_node_ptr var1_; |
| }; |
| |
| template <typename T> |
| class swap_generic_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef ivariable<T>* ivariable_ptr; |
| |
| swap_generic_node(expression_ptr var0, expression_ptr var1) |
| : binary_node<T>(details::e_swap,var0,var1), |
| var0_(dynamic_cast<ivariable_ptr>(var0)), |
| var1_(dynamic_cast<ivariable_ptr>(var1)) |
| {} |
| |
| inline T value() const |
| { |
| std::swap(var0_->ref(),var1_->ref()); |
| return var1_->ref(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_swap; |
| } |
| |
| private: |
| |
| ivariable_ptr var0_; |
| ivariable_ptr var1_; |
| }; |
| |
| template <typename T> |
| class swap_vecvec_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| swap_vecvec_node(expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(details::e_swap,branch0,branch1), |
| vec0_node_ptr_(0), |
| vec1_node_ptr_(0), |
| vec_size_ (0), |
| initialised_ (false) |
| { |
| if (is_ivector_node(binary_node<T>::branch_[0].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) |
| { |
| vec0_node_ptr_ = vi->vec(); |
| vds() = vi->vds(); |
| } |
| } |
| |
| if (is_ivector_node(binary_node<T>::branch_[1].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) |
| { |
| vec1_node_ptr_ = vi->vec(); |
| } |
| } |
| |
| if (vec0_node_ptr_ && vec1_node_ptr_) |
| { |
| vec_size_ = std::min(vec0_node_ptr_->vds().size(), |
| vec1_node_ptr_->vds().size()); |
| |
| initialised_ = true; |
| } |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vec1_node_ptr_->vds().data(); |
| |
| for (std::size_t i = 0; i < vec_size_; ++i) |
| { |
| std::swap(vec0[i],vec1[i]); |
| } |
| |
| return vec1_node_ptr_->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return vec0_node_ptr_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return vec0_node_ptr_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvecswap; |
| } |
| |
| std::size_t size() const |
| { |
| return vec_size_; |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node<T>* vec0_node_ptr_; |
| vector_node<T>* vec1_node_ptr_; |
| std::size_t vec_size_; |
| bool initialised_; |
| vds_t vds_; |
| }; |
| |
| #ifndef exprtk_disable_string_capabilities |
| template <typename T> |
| class stringvar_node : public expression_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef range_pack<T> range_t; |
| |
| static std::string null_value; |
| |
| explicit stringvar_node() |
| : value_(&null_value) |
| {} |
| |
| explicit stringvar_node(std::string& v) |
| : value_(&v) |
| { |
| rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1); |
| rp_.cache.first = rp_.n0_c.second; |
| rp_.cache.second = rp_.n1_c.second; |
| } |
| |
| inline bool operator <(const stringvar_node<T>& v) const |
| { |
| return this < (&v); |
| } |
| |
| inline T value() const |
| { |
| rp_.n1_c.second = (*value_).size() - 1; |
| rp_.cache.second = rp_.n1_c.second; |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return ref(); |
| } |
| |
| const char* base() const |
| { |
| return &(*value_)[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return ref().size(); |
| } |
| |
| std::string& ref() |
| { |
| return (*value_); |
| } |
| |
| const std::string& ref() const |
| { |
| return (*value_); |
| } |
| |
| range_t& range_ref() |
| { |
| return rp_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return rp_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_stringvar; |
| } |
| |
| private: |
| |
| std::string* value_; |
| mutable range_t rp_; |
| }; |
| |
| template <typename T> |
| std::string stringvar_node<T>::null_value = std::string(""); |
| |
| template <typename T> |
| class string_range_node : public expression_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef range_pack<T> range_t; |
| |
| static std::string null_value; |
| |
| explicit string_range_node(std::string& v, const range_t& rp) |
| : value_(&v), |
| rp_(rp) |
| {} |
| |
| virtual ~string_range_node() |
| { |
| rp_.free(); |
| } |
| |
| inline bool operator <(const string_range_node<T>& v) const |
| { |
| return this < (&v); |
| } |
| |
| inline T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline std::string str() const |
| { |
| return (*value_); |
| } |
| |
| const char* base() const |
| { |
| return &(*value_)[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return ref().size(); |
| } |
| |
| inline range_t range() const |
| { |
| return rp_; |
| } |
| |
| inline virtual std::string& ref() |
| { |
| return (*value_); |
| } |
| |
| inline virtual const std::string& ref() const |
| { |
| return (*value_); |
| } |
| |
| inline range_t& range_ref() |
| { |
| return rp_; |
| } |
| |
| inline const range_t& range_ref() const |
| { |
| return rp_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_stringvarrng; |
| } |
| |
| private: |
| |
| std::string* value_; |
| range_t rp_; |
| }; |
| |
| template <typename T> |
| std::string string_range_node<T>::null_value = std::string(""); |
| |
| template <typename T> |
| class const_string_range_node : public expression_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef range_pack<T> range_t; |
| |
| explicit const_string_range_node(const std::string& v, const range_t& rp) |
| : value_(v), |
| rp_(rp) |
| {} |
| |
| ~const_string_range_node() |
| { |
| rp_.free(); |
| } |
| |
| inline T value() const |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return value_.data(); |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t range() const |
| { |
| return rp_; |
| } |
| |
| range_t& range_ref() |
| { |
| return rp_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return rp_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_cstringvarrng; |
| } |
| |
| private: |
| |
| const_string_range_node<T>& operator=(const const_string_range_node<T>&); |
| |
| const std::string value_; |
| range_t rp_; |
| }; |
| |
| template <typename T> |
| class generic_string_range_node : public expression_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef stringvar_node <T>* strvar_node_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| generic_string_range_node(expression_ptr str_branch, const range_t& brange) |
| : initialised_(false), |
| branch_(str_branch), |
| branch_deletable_(branch_deletable(branch_)), |
| str_base_ptr_ (0), |
| str_range_ptr_(0), |
| base_range_(brange) |
| { |
| range_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.n1_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.cache.first = range_.n0_c.second; |
| range_.cache.second = range_.n1_c.second; |
| |
| if (is_generally_string_node(branch_)) |
| { |
| str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_); |
| |
| if (0 == str_base_ptr_) |
| return; |
| |
| str_range_ptr_ = dynamic_cast<irange_ptr>(branch_); |
| |
| if (0 == str_range_ptr_) |
| return; |
| } |
| |
| initialised_ = (str_base_ptr_ && str_range_ptr_); |
| } |
| |
| ~generic_string_range_node() |
| { |
| base_range_.free(); |
| |
| if (branch_ && branch_deletable_) |
| { |
| delete branch_; |
| branch_ = 0; |
| } |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| branch_->value(); |
| |
| std::size_t str_r0 = 0; |
| std::size_t str_r1 = 0; |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| range_t& range = str_range_ptr_->range_ref(); |
| |
| const std::size_t base_str_size = str_base_ptr_->size(); |
| |
| if ( |
| range (str_r0,str_r1,base_str_size) && |
| base_range_( r0, r1,base_str_size) |
| ) |
| { |
| const std::size_t size = (r1 - r0) + 1; |
| |
| range_.n1_c.second = size - 1; |
| range_.cache.second = range_.n1_c.second; |
| |
| value_.assign(str_base_ptr_->base() + str_r0 + r0, size); |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return &value_[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return range_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return range_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strgenrange; |
| } |
| |
| private: |
| |
| bool initialised_; |
| expression_ptr branch_; |
| bool branch_deletable_; |
| str_base_ptr str_base_ptr_; |
| irange_ptr str_range_ptr_; |
| mutable range_t base_range_; |
| mutable range_t range_; |
| mutable std::string value_; |
| }; |
| |
| template <typename T> |
| class string_concat_node : public binary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| string_concat_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| initialised_(false), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_range_ptr_(0), |
| str1_range_ptr_(0) |
| { |
| range_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.n1_c = std::make_pair<bool,std::size_t>(true,0); |
| |
| range_.cache.first = range_.n0_c.second; |
| range_.cache.second = range_.n1_c.second; |
| |
| if (is_generally_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_base_ptr_) |
| return; |
| |
| str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_range_ptr_) |
| return; |
| } |
| |
| if (is_generally_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| str1_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_range_ptr_) |
| return; |
| } |
| |
| initialised_ = str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_range_ptr_ && |
| str1_range_ptr_ ; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::size_t str0_r0 = 0; |
| std::size_t str0_r1 = 0; |
| |
| std::size_t str1_r0 = 0; |
| std::size_t str1_r1 = 0; |
| |
| range_t& range0 = str0_range_ptr_->range_ref(); |
| range_t& range1 = str1_range_ptr_->range_ref(); |
| |
| if ( |
| range0(str0_r0,str0_r1,str0_base_ptr_->size()) && |
| range1(str1_r0,str1_r1,str1_base_ptr_->size()) |
| ) |
| { |
| const std::size_t size0 = (str0_r1 - str0_r0) + 1; |
| const std::size_t size1 = (str1_r1 - str1_r0) + 1; |
| |
| value_.assign(str0_base_ptr_->base() + str0_r0, size0); |
| value_.append(str1_base_ptr_->base() + str1_r0, size1); |
| |
| range_.n1_c.second = value_.size() - 1; |
| range_.cache.second = range_.n1_c.second; |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return &value_[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return range_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return range_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strconcat; |
| } |
| |
| private: |
| |
| bool initialised_; |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| irange_ptr str0_range_ptr_; |
| irange_ptr str1_range_ptr_; |
| mutable range_t range_; |
| mutable std::string value_; |
| }; |
| |
| template <typename T> |
| class swap_string_node : public binary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef stringvar_node <T>* strvar_node_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| swap_string_node(expression_ptr branch0, expression_ptr branch1) |
| : binary_node<T>(details::e_swap,branch0,branch1), |
| initialised_(false), |
| str0_node_ptr_(0), |
| str1_node_ptr_(0) |
| { |
| if (is_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first); |
| } |
| |
| if (is_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[1].first); |
| } |
| |
| initialised_ = (str0_node_ptr_ && str1_node_ptr_); |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::swap(str0_node_ptr_->ref(),str1_node_ptr_->ref()); |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return str0_node_ptr_->str(); |
| } |
| |
| const char* base() const |
| { |
| return str0_node_ptr_->base(); |
| } |
| |
| std::size_t size() const |
| { |
| return str0_node_ptr_->size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| const range_t& range_ref() const |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strswap; |
| } |
| |
| private: |
| |
| bool initialised_; |
| strvar_node_ptr str0_node_ptr_; |
| strvar_node_ptr str1_node_ptr_; |
| }; |
| |
| template <typename T> |
| class swap_genstrings_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| swap_genstrings_node(expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(details::e_default,branch0,branch1), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_range_ptr_(0), |
| str1_range_ptr_(0), |
| initialised_(false) |
| { |
| if (is_generally_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str0_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| if (is_generally_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str1_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| initialised_ = str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_range_ptr_ && |
| str1_range_ptr_ ; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::size_t str0_r0 = 0; |
| std::size_t str0_r1 = 0; |
| |
| std::size_t str1_r0 = 0; |
| std::size_t str1_r1 = 0; |
| |
| range_t& range0 = (*str0_range_ptr_); |
| range_t& range1 = (*str1_range_ptr_); |
| |
| if ( |
| range0(str0_r0,str0_r1,str0_base_ptr_->size()) && |
| range1(str1_r0,str1_r1,str1_base_ptr_->size()) |
| ) |
| { |
| const std::size_t size0 = range0.cache_size(); |
| const std::size_t size1 = range1.cache_size(); |
| const std::size_t max_size = std::min(size0,size1); |
| |
| char* s0 = const_cast<char*>(str0_base_ptr_->base() + str0_r0); |
| char* s1 = const_cast<char*>(str1_base_ptr_->base() + str1_r0); |
| |
| loop_unroll::details lud(max_size); |
| const char* upper_bound = s0 + lud.upper_bound; |
| |
| while (s0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| std::swap(s0[N], s1[N]); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| s0 += lud.batch_size; |
| s1 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { std::swap(s0[i],s1[i]); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strswap; |
| } |
| |
| private: |
| |
| swap_genstrings_node(swap_genstrings_node<T>&); |
| swap_genstrings_node<T>& operator=(swap_genstrings_node<T>&); |
| |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| range_ptr str0_range_ptr_; |
| range_ptr str1_range_ptr_; |
| bool initialised_; |
| }; |
| |
| template <typename T> |
| class stringvar_size_node : public expression_node<T> |
| { |
| public: |
| |
| static std::string null_value; |
| |
| explicit stringvar_size_node() |
| : value_(&null_value) |
| {} |
| |
| explicit stringvar_size_node(std::string& v) |
| : value_(&v) |
| {} |
| |
| inline T value() const |
| { |
| return T((*value_).size()); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_stringvarsize; |
| } |
| |
| private: |
| |
| std::string* value_; |
| }; |
| |
| template <typename T> |
| std::string stringvar_size_node<T>::null_value = std::string(""); |
| |
| template <typename T> |
| class string_size_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| |
| string_size_node(expression_ptr brnch) |
| : branch_(brnch), |
| branch_deletable_(branch_deletable(branch_)), |
| str_base_ptr_(0) |
| { |
| if (is_generally_string_node(branch_)) |
| { |
| str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_); |
| |
| if (0 == str_base_ptr_) |
| return; |
| } |
| } |
| |
| ~string_size_node() |
| { |
| if (branch_ && branch_deletable_) |
| { |
| delete branch_; |
| branch_ = 0; |
| } |
| } |
| |
| inline T value() const |
| { |
| T result = std::numeric_limits<T>::quiet_NaN(); |
| |
| if (str_base_ptr_) |
| { |
| branch_->value(); |
| result = T(str_base_ptr_->size()); |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_stringsize; |
| } |
| |
| private: |
| |
| expression_ptr branch_; |
| bool branch_deletable_; |
| str_base_ptr str_base_ptr_; |
| }; |
| |
| struct asn_assignment |
| { |
| static inline void execute(std::string& s, const char* data, const std::size_t size) |
| { s.assign(data,size); } |
| }; |
| |
| struct asn_addassignment |
| { |
| static inline void execute(std::string& s, const char* data, const std::size_t size) |
| { s.append(data,size); } |
| }; |
| |
| template <typename T, typename AssignmentProcess = asn_assignment> |
| class assignment_string_node : public binary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef stringvar_node <T>* strvar_node_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| assignment_string_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| initialised_(false), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_node_ptr_ (0), |
| str1_range_ptr_(0) |
| { |
| if (is_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first); |
| |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| } |
| |
| if (is_generally_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str1_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| initialised_ = str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_node_ptr_ && |
| str1_range_ptr_ ; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| range_t& range = (*str1_range_ptr_); |
| |
| if (range(r0,r1,str1_base_ptr_->size())) |
| { |
| AssignmentProcess::execute(str0_node_ptr_->ref(), |
| str1_base_ptr_->base() + r0, |
| (r1 - r0) + 1); |
| |
| binary_node<T>::branch_[0].first->value(); |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return str0_node_ptr_->str(); |
| } |
| |
| const char* base() const |
| { |
| return str0_node_ptr_->base(); |
| } |
| |
| std::size_t size() const |
| { |
| return str0_node_ptr_->size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| const range_t& range_ref() const |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strass; |
| } |
| |
| private: |
| |
| bool initialised_; |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| strvar_node_ptr str0_node_ptr_; |
| range_ptr str1_range_ptr_; |
| }; |
| |
| template <typename T, typename AssignmentProcess = asn_assignment> |
| class assignment_string_range_node : public binary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef stringvar_node <T>* strvar_node_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| assignment_string_range_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| initialised_(false), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_node_ptr_ (0), |
| str0_range_ptr_(0), |
| str1_range_ptr_(0) |
| { |
| if (is_string_range_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first); |
| |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str0_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| if (is_generally_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str1_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| initialised_ = str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_node_ptr_ && |
| str0_range_ptr_ && |
| str1_range_ptr_ ; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::size_t s0_r0 = 0; |
| std::size_t s0_r1 = 0; |
| |
| std::size_t s1_r0 = 0; |
| std::size_t s1_r1 = 0; |
| |
| range_t& range0 = (*str0_range_ptr_); |
| range_t& range1 = (*str1_range_ptr_); |
| |
| if ( |
| range0(s0_r0,s0_r1,str0_base_ptr_->size()) && |
| range1(s1_r0,s1_r1,str1_base_ptr_->size()) |
| ) |
| { |
| std::size_t size = std::min((s0_r1 - s0_r0),(s1_r1 - s1_r0)) + 1; |
| |
| std::copy(str1_base_ptr_->base() + s1_r0, |
| str1_base_ptr_->base() + s1_r0 + size, |
| const_cast<char*>(base() + s0_r0)); |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return str0_node_ptr_->str(); |
| } |
| |
| const char* base() const |
| { |
| return str0_node_ptr_->base(); |
| } |
| |
| std::size_t size() const |
| { |
| return str0_node_ptr_->size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| const range_t& range_ref() const |
| { |
| return str0_node_ptr_->range_ref(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strass; |
| } |
| |
| private: |
| |
| bool initialised_; |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| strvar_node_ptr str0_node_ptr_; |
| range_ptr str0_range_ptr_; |
| range_ptr str1_range_ptr_; |
| }; |
| |
| template <typename T> |
| class conditional_string_node : public trinary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| conditional_string_node(expression_ptr test, |
| expression_ptr consequent, |
| expression_ptr alternative) |
| : trinary_node<T>(details::e_default,consequent,alternative,test), |
| initialised_(false), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_range_ptr_(0), |
| str1_range_ptr_(0), |
| test_ (test), |
| consequent_ (consequent), |
| alternative_(alternative) |
| { |
| range_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.n1_c = std::make_pair<bool,std::size_t>(true,0); |
| |
| range_.cache.first = range_.n0_c.second; |
| range_.cache.second = range_.n1_c.second; |
| |
| if (is_generally_string_node(trinary_node<T>::branch_[0].first)) |
| { |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(trinary_node<T>::branch_[0].first); |
| |
| if (0 == str0_base_ptr_) |
| return; |
| |
| str0_range_ptr_ = dynamic_cast<irange_ptr>(trinary_node<T>::branch_[0].first); |
| |
| if (0 == str0_range_ptr_) |
| return; |
| } |
| |
| if (is_generally_string_node(trinary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(trinary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| str1_range_ptr_ = dynamic_cast<irange_ptr>(trinary_node<T>::branch_[1].first); |
| |
| if (0 == str1_range_ptr_) |
| return; |
| } |
| |
| initialised_ = str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_range_ptr_ && |
| str1_range_ptr_ ; |
| |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| if (is_true(test_)) |
| { |
| consequent_->value(); |
| |
| range_t& range = str0_range_ptr_->range_ref(); |
| |
| if (range(r0,r1,str0_base_ptr_->size())) |
| { |
| const std::size_t size = (r1 - r0) + 1; |
| |
| value_.assign(str0_base_ptr_->base() + r0, size); |
| |
| range_.n1_c.second = value_.size() - 1; |
| range_.cache.second = range_.n1_c.second; |
| |
| return T(1); |
| } |
| } |
| else |
| { |
| alternative_->value(); |
| |
| range_t& range = str1_range_ptr_->range_ref(); |
| |
| if (range(r0,r1,str1_base_ptr_->size())) |
| { |
| const std::size_t size = (r1 - r0) + 1; |
| |
| value_.assign(str1_base_ptr_->base() + r0, size); |
| |
| range_.n1_c.second = value_.size() - 1; |
| range_.cache.second = range_.n1_c.second; |
| |
| return T(0); |
| } |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return &value_[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return range_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return range_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strcondition; |
| } |
| |
| private: |
| |
| bool initialised_; |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| irange_ptr str0_range_ptr_; |
| irange_ptr str1_range_ptr_; |
| mutable range_t range_; |
| mutable std::string value_; |
| |
| expression_ptr test_; |
| expression_ptr consequent_; |
| expression_ptr alternative_; |
| }; |
| |
| template <typename T> |
| class cons_conditional_str_node : public binary_node <T>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| cons_conditional_str_node(expression_ptr test, |
| expression_ptr consequent) |
| : binary_node<T>(details::e_default,consequent,test), |
| initialised_(false), |
| str0_base_ptr_ (0), |
| str0_range_ptr_(0), |
| test_ (test), |
| consequent_(consequent) |
| { |
| range_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.n1_c = std::make_pair<bool,std::size_t>(true,0); |
| |
| range_.cache.first = range_.n0_c.second; |
| range_.cache.second = range_.n1_c.second; |
| |
| if (is_generally_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_base_ptr_) |
| return; |
| |
| str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_range_ptr_) |
| return; |
| } |
| |
| initialised_ = str0_base_ptr_ && str0_range_ptr_ ; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| if (is_true(test_)) |
| { |
| consequent_->value(); |
| |
| range_t& range = str0_range_ptr_->range_ref(); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| if (range(r0,r1,str0_base_ptr_->size())) |
| { |
| const std::size_t size = (r1 - r0) + 1; |
| |
| value_.assign(str0_base_ptr_->base() + r0, size); |
| |
| range_.n1_c.second = value_.size() - 1; |
| range_.cache.second = range_.n1_c.second; |
| |
| return T(1); |
| } |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| std::string str() const |
| { |
| return value_; |
| } |
| |
| const char* base() const |
| { |
| return &value_[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return value_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return range_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return range_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strccondition; |
| } |
| |
| private: |
| |
| bool initialised_; |
| str_base_ptr str0_base_ptr_; |
| irange_ptr str0_range_ptr_; |
| mutable range_t range_; |
| mutable std::string value_; |
| |
| expression_ptr test_; |
| expression_ptr consequent_; |
| }; |
| #endif |
| |
| template <typename T, std::size_t N> |
| inline T axn(T a, T x) |
| { |
| // a*x^n |
| return a * exprtk::details::numeric::fast_exp<T,N>::result(x); |
| } |
| |
| template <typename T, std::size_t N> |
| inline T axnb(T a, T x, T b) |
| { |
| // a*x^n+b |
| return a * exprtk::details::numeric::fast_exp<T,N>::result(x) + b; |
| } |
| |
| template <typename T> |
| struct sf_base |
| { |
| typedef typename details::functor_t<T>::Type Type; |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::qfunc_t quaternary_functor_t; |
| typedef typename functor_t::tfunc_t trinary_functor_t; |
| typedef typename functor_t::bfunc_t binary_functor_t; |
| typedef typename functor_t::ufunc_t unary_functor_t; |
| }; |
| |
| #define define_sfop3(NN,OP0,OP1) \ |
| template <typename T> \ |
| struct sf##NN##_op : public sf_base<T> \ |
| { \ |
| typedef typename sf_base<T>::Type Type; \ |
| static inline T process(Type x, Type y, Type z) \ |
| { \ |
| return (OP0); \ |
| } \ |
| static inline std::string id() \ |
| { \ |
| return OP1; \ |
| } \ |
| }; \ |
| |
| define_sfop3(00,(x + y) / z ,"(t+t)/t") |
| define_sfop3(01,(x + y) * z ,"(t+t)*t") |
| define_sfop3(02,(x + y) - z ,"(t+t)-t") |
| define_sfop3(03,(x + y) + z ,"(t+t)+t") |
| define_sfop3(04,(x - y) + z ,"(t-t)+t") |
| define_sfop3(05,(x - y) / z ,"(t-t)/t") |
| define_sfop3(06,(x - y) * z ,"(t-t)*t") |
| define_sfop3(07,(x * y) + z ,"(t*t)+t") |
| define_sfop3(08,(x * y) - z ,"(t*t)-t") |
| define_sfop3(09,(x * y) / z ,"(t*t)/t") |
| define_sfop3(10,(x * y) * z ,"(t*t)*t") |
| define_sfop3(11,(x / y) + z ,"(t/t)+t") |
| define_sfop3(12,(x / y) - z ,"(t/t)-t") |
| define_sfop3(13,(x / y) / z ,"(t/t)/t") |
| define_sfop3(14,(x / y) * z ,"(t/t)*t") |
| define_sfop3(15,x / (y + z) ,"t/(t+t)") |
| define_sfop3(16,x / (y - z) ,"t/(t-t)") |
| define_sfop3(17,x / (y * z) ,"t/(t*t)") |
| define_sfop3(18,x / (y / z) ,"t/(t/t)") |
| define_sfop3(19,x * (y + z) ,"t*(t+t)") |
| define_sfop3(20,x * (y - z) ,"t*(t-t)") |
| define_sfop3(21,x * (y * z) ,"t*(t*t)") |
| define_sfop3(22,x * (y / z) ,"t*(t/t)") |
| define_sfop3(23,x - (y + z) ,"t-(t+t)") |
| define_sfop3(24,x - (y - z) ,"t-(t-t)") |
| define_sfop3(25,x - (y / z) ,"t-(t/t)") |
| define_sfop3(26,x - (y * z) ,"t-(t*t)") |
| define_sfop3(27,x + (y * z) ,"t+(t*t)") |
| define_sfop3(28,x + (y / z) ,"t+(t/t)") |
| define_sfop3(29,x + (y + z) ,"t+(t+t)") |
| define_sfop3(30,x + (y - z) ,"t+(t-t)") |
| define_sfop3(31,(axnb<T,2>(x,y,z))," ") |
| define_sfop3(32,(axnb<T,3>(x,y,z))," ") |
| define_sfop3(33,(axnb<T,4>(x,y,z))," ") |
| define_sfop3(34,(axnb<T,5>(x,y,z))," ") |
| define_sfop3(35,(axnb<T,6>(x,y,z))," ") |
| define_sfop3(36,(axnb<T,7>(x,y,z))," ") |
| define_sfop3(37,(axnb<T,8>(x,y,z))," ") |
| define_sfop3(38,(axnb<T,9>(x,y,z))," ") |
| define_sfop3(39,x * numeric::log(y) + z,"") |
| define_sfop3(40,x * numeric::log(y) - z,"") |
| define_sfop3(41,x * numeric::log10(y) + z,"") |
| define_sfop3(42,x * numeric::log10(y) - z,"") |
| define_sfop3(43,x * numeric::sin(y) + z ,"") |
| define_sfop3(44,x * numeric::sin(y) - z ,"") |
| define_sfop3(45,x * numeric::cos(y) + z ,"") |
| define_sfop3(46,x * numeric::cos(y) - z ,"") |
| define_sfop3(47,details::is_true(x) ? y : z,"") |
| |
| #define define_sfop4(NN,OP0,OP1) \ |
| template <typename T> \ |
| struct sf##NN##_op : public sf_base<T> \ |
| { \ |
| typedef typename sf_base<T>::Type Type; \ |
| static inline T process(Type x, Type y, Type z, Type w) \ |
| { \ |
| return (OP0); \ |
| } \ |
| static inline std::string id() { return OP1; } \ |
| }; \ |
| |
| define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") |
| define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") |
| define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") |
| define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") |
| define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") |
| define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") |
| define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") |
| define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") |
| define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") |
| define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") |
| define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") |
| define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") |
| define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") |
| define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") |
| define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") |
| define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") |
| define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") |
| define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") |
| define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") |
| define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") |
| define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") |
| define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") |
| define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") |
| define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") |
| define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") |
| define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") |
| define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") |
| define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") |
| define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") |
| define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") |
| define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") |
| define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") |
| define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") |
| define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") |
| define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") |
| define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") |
| |
| define_sfop4(84,(axn<T,2>(x,y) + axn<T,2>(z,w)),"") |
| define_sfop4(85,(axn<T,3>(x,y) + axn<T,3>(z,w)),"") |
| define_sfop4(86,(axn<T,4>(x,y) + axn<T,4>(z,w)),"") |
| define_sfop4(87,(axn<T,5>(x,y) + axn<T,5>(z,w)),"") |
| define_sfop4(88,(axn<T,6>(x,y) + axn<T,6>(z,w)),"") |
| define_sfop4(89,(axn<T,7>(x,y) + axn<T,7>(z,w)),"") |
| define_sfop4(90,(axn<T,8>(x,y) + axn<T,8>(z,w)),"") |
| define_sfop4(91,(axn<T,9>(x,y) + axn<T,9>(z,w)),"") |
| define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") |
| define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") |
| define_sfop4(94,((x < y) ? z : w),"") |
| define_sfop4(95,((x <= y) ? z : w),"") |
| define_sfop4(96,((x > y) ? z : w),"") |
| define_sfop4(97,((x >= y) ? z : w),"") |
| define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") |
| define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") |
| |
| define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") |
| define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") |
| define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") |
| define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") |
| define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") |
| define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") |
| define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") |
| define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") |
| define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") |
| define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") |
| define_sfop4(ext10,((x + y) * (z - w)),"(t+t)*(t-t)") |
| define_sfop4(ext11,((x + y) / (z - w)),"(t+t)/(t-t)") |
| define_sfop4(ext12,((x - y) - (z + w)),"(t-t)-(t+t)") |
| define_sfop4(ext13,((x - y) + (z + w)),"(t-t)+(t+t)") |
| define_sfop4(ext14,((x - y) * (z + w)),"(t-t)*(t+t)") |
| define_sfop4(ext15,((x - y) / (z + w)),"(t-t)/(t+t)") |
| define_sfop4(ext16,((x * y) - (z + w)),"(t*t)-(t+t)") |
| define_sfop4(ext17,((x / y) - (z + w)),"(t/t)-(t+t)") |
| define_sfop4(ext18,((x * y) + (z + w)),"(t*t)+(t+t)") |
| define_sfop4(ext19,((x / y) + (z + w)),"(t/t)+(t+t)") |
| define_sfop4(ext20,((x * y) + (z - w)),"(t*t)+(t-t)") |
| define_sfop4(ext21,((x / y) + (z - w)),"(t/t)+(t-t)") |
| define_sfop4(ext22,((x * y) - (z - w)),"(t*t)-(t-t)") |
| define_sfop4(ext23,((x / y) - (z - w)),"(t/t)-(t-t)") |
| define_sfop4(ext24,((x + y) * (z * w)),"(t+t)*(t*t)") |
| define_sfop4(ext25,((x + y) * (z / w)),"(t+t)*(t/t)") |
| define_sfop4(ext26,((x + y) / (z * w)),"(t+t)/(t*t)") |
| define_sfop4(ext27,((x + y) / (z / w)),"(t+t)/(t/t)") |
| define_sfop4(ext28,((x - y) / (z * w)),"(t-t)/(t*t)") |
| define_sfop4(ext29,((x - y) / (z / w)),"(t-t)/(t/t)") |
| define_sfop4(ext30,((x - y) * (z * w)),"(t-t)*(t*t)") |
| define_sfop4(ext31,((x - y) * (z / w)),"(t-t)*(t/t)") |
| define_sfop4(ext32,((x * y) * (z + w)),"(t*t)*(t+t)") |
| define_sfop4(ext33,((x / y) * (z + w)),"(t/t)*(t+t)") |
| define_sfop4(ext34,((x * y) / (z + w)),"(t*t)/(t+t)") |
| define_sfop4(ext35,((x / y) / (z + w)),"(t/t)/(t+t)") |
| define_sfop4(ext36,((x * y) / (z - w)),"(t*t)/(t-t)") |
| define_sfop4(ext37,((x / y) / (z - w)),"(t/t)/(t-t)") |
| define_sfop4(ext38,((x * y) * (z - w)),"(t*t)*(t-t)") |
| define_sfop4(ext39,((x * y) / (z * w)),"(t*t)/(t*t)") |
| define_sfop4(ext40,((x / y) * (z / w)),"(t/t)*(t/t)") |
| define_sfop4(ext41,((x / y) * (z - w)),"(t/t)*(t-t)") |
| define_sfop4(ext42,((x * y) * (z * w)),"(t*t)*(t*t)") |
| define_sfop4(ext43,(x + (y * (z / w))),"t+(t*(t/t))") |
| define_sfop4(ext44,(x - (y * (z / w))),"t-(t*(t/t))") |
| define_sfop4(ext45,(x + (y / (z * w))),"t+(t/(t*t))") |
| define_sfop4(ext46,(x - (y / (z * w))),"t-(t/(t*t))") |
| define_sfop4(ext47,(((x - y) - z) * w),"((t-t)-t)*t") |
| define_sfop4(ext48,(((x - y) - z) / w),"((t-t)-t)/t") |
| define_sfop4(ext49,(((x - y) + z) * w),"((t-t)+t)*t") |
| define_sfop4(ext50,(((x - y) + z) / w),"((t-t)+t)/t") |
| define_sfop4(ext51,((x + (y - z)) * w),"(t+(t-t))*t") |
| define_sfop4(ext52,((x + (y - z)) / w),"(t+(t-t))/t") |
| define_sfop4(ext53,((x + y) / (z + w)),"(t+t)/(t+t)") |
| define_sfop4(ext54,((x - y) / (z - w)),"(t-t)/(t-t)") |
| define_sfop4(ext55,((x + y) * (z + w)),"(t+t)*(t+t)") |
| define_sfop4(ext56,((x - y) * (z - w)),"(t-t)*(t-t)") |
| define_sfop4(ext57,((x - y) + (z - w)),"(t-t)+(t-t)") |
| define_sfop4(ext58,((x - y) - (z - w)),"(t-t)-(t-t)") |
| define_sfop4(ext59,((x / y) + (z * w)),"(t/t)+(t*t)") |
| define_sfop4(ext60,(((x * y) * z) / w),"((t*t)*t)/t") |
| |
| #undef define_sfop3 |
| #undef define_sfop4 |
| |
| template <typename T, typename SpecialFunction> |
| class sf3_node : public trinary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| sf3_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1, |
| expression_ptr branch2) |
| : trinary_node<T>(opr,branch0,branch1,branch2) |
| {} |
| |
| inline T value() const |
| { |
| const T x = trinary_node<T>::branch_[0].first->value(); |
| const T y = trinary_node<T>::branch_[1].first->value(); |
| const T z = trinary_node<T>::branch_[2].first->value(); |
| |
| return SpecialFunction::process(x,y,z); |
| } |
| }; |
| |
| template <typename T, typename SpecialFunction> |
| class sf4_node : public quaternary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| sf4_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1, |
| expression_ptr branch2, |
| expression_ptr branch3) |
| : quaternary_node<T>(opr,branch0,branch1,branch2,branch3) |
| {} |
| |
| inline T value() const |
| { |
| const T x = quaternary_node<T>::branch_[0].first->value(); |
| const T y = quaternary_node<T>::branch_[1].first->value(); |
| const T z = quaternary_node<T>::branch_[2].first->value(); |
| const T w = quaternary_node<T>::branch_[3].first->value(); |
| |
| return SpecialFunction::process(x,y,z,w); |
| } |
| }; |
| |
| template <typename T, typename SpecialFunction> |
| class sf3_var_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| sf3_var_node(const T& v0, const T& v1, const T& v2) |
| : v0_(v0), |
| v1_(v1), |
| v2_(v2) |
| {} |
| |
| inline T value() const |
| { |
| return SpecialFunction::process(v0_,v1_,v2_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_trinary; |
| } |
| |
| private: |
| |
| sf3_var_node(sf3_var_node<T,SpecialFunction>&); |
| sf3_var_node<T,SpecialFunction>& operator=(sf3_var_node<T,SpecialFunction>&); |
| |
| const T& v0_; |
| const T& v1_; |
| const T& v2_; |
| }; |
| |
| template <typename T, typename SpecialFunction> |
| class sf4_var_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) |
| : v0_(v0), |
| v1_(v1), |
| v2_(v2), |
| v3_(v3) |
| {} |
| |
| inline T value() const |
| { |
| return SpecialFunction::process(v0_,v1_,v2_,v3_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_trinary; |
| } |
| |
| private: |
| |
| sf4_var_node(sf4_var_node<T,SpecialFunction>&); |
| sf4_var_node<T,SpecialFunction>& operator=(sf4_var_node<T,SpecialFunction>&); |
| |
| const T& v0_; |
| const T& v1_; |
| const T& v2_; |
| const T& v3_; |
| }; |
| |
| template <typename T, typename VarArgFunction> |
| class vararg_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) |
| { |
| arg_list_.resize(arg_list.size()); |
| delete_branch_.resize(arg_list.size()); |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (arg_list[i]) |
| { |
| arg_list_[i] = arg_list[i]; |
| delete_branch_[i] = static_cast<unsigned char>(branch_deletable(arg_list_[i]) ? 1 : 0); |
| } |
| else |
| { |
| arg_list_.clear(); |
| delete_branch_.clear(); |
| return; |
| } |
| } |
| } |
| |
| ~vararg_node() |
| { |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| if (arg_list_[i] && delete_branch_[i]) |
| { |
| delete arg_list_[i]; |
| arg_list_[i] = 0; |
| } |
| } |
| } |
| |
| inline T value() const |
| { |
| if (!arg_list_.empty()) |
| return VarArgFunction::process(arg_list_); |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vararg; |
| } |
| |
| private: |
| |
| std::vector<expression_ptr> arg_list_; |
| std::vector<unsigned char> delete_branch_; |
| }; |
| |
| template <typename T, typename VarArgFunction> |
| class vararg_varnode : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list) |
| { |
| arg_list_.resize(arg_list.size()); |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (arg_list[i] && is_variable_node(arg_list[i])) |
| { |
| variable_node<T>* var_node_ptr = static_cast<variable_node<T>*>(arg_list[i]); |
| arg_list_[i] = (&var_node_ptr->ref()); |
| } |
| else |
| { |
| arg_list_.clear(); |
| return; |
| } |
| } |
| } |
| |
| inline T value() const |
| { |
| if (!arg_list_.empty()) |
| return VarArgFunction::process(arg_list_); |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vararg; |
| } |
| |
| private: |
| |
| std::vector<const T*> arg_list_; |
| }; |
| |
| template <typename T, typename VecFunction> |
| class vectorize_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| vectorize_node(const expression_ptr v) |
| : ivec_ptr_(0), |
| v_(v), |
| v_deletable_(branch_deletable(v_)) |
| { |
| if (is_ivector_node(v)) |
| { |
| ivec_ptr_ = dynamic_cast<vector_interface<T>*>(v); |
| } |
| else |
| ivec_ptr_ = 0; |
| } |
| |
| ~vectorize_node() |
| { |
| if (v_ && v_deletable_) |
| { |
| delete v_; |
| } |
| } |
| |
| inline T value() const |
| { |
| if (ivec_ptr_) |
| { |
| v_->value(); |
| return VecFunction::process(ivec_ptr_); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecfunc; |
| } |
| |
| private: |
| |
| vector_interface<T>* ivec_ptr_; |
| expression_ptr v_; |
| bool v_deletable_; |
| }; |
| |
| template <typename T> |
| class assignment_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| var_node_ptr_(0) |
| { |
| if (is_variable_node(binary_node<T>::branch_[0].first)) |
| { |
| var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (var_node_ptr_) |
| { |
| T& result = var_node_ptr_->ref(); |
| |
| result = binary_node<T>::branch_[1].first->value(); |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| variable_node<T>* var_node_ptr_; |
| }; |
| |
| template <typename T> |
| class assignment_vec_elem_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_vec_elem_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec_node_ptr_(0) |
| { |
| if (is_vector_elem_node(binary_node<T>::branch_[0].first)) |
| { |
| vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (vec_node_ptr_) |
| { |
| T& result = vec_node_ptr_->ref(); |
| |
| result = binary_node<T>::branch_[1].first->value(); |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| vector_elem_node<T>* vec_node_ptr_; |
| }; |
| |
| template <typename T> |
| class assignment_rebasevec_elem_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_rebasevec_elem_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| rbvec_node_ptr_(0) |
| { |
| if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) |
| { |
| rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (rbvec_node_ptr_) |
| { |
| T& result = rbvec_node_ptr_->ref(); |
| |
| result = binary_node<T>::branch_[1].first->value(); |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| rebasevector_elem_node<T>* rbvec_node_ptr_; |
| }; |
| |
| template <typename T> |
| class assignment_rebasevec_celem_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_rebasevec_celem_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| rbvec_node_ptr_(0) |
| { |
| if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) |
| { |
| rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (rbvec_node_ptr_) |
| { |
| T& result = rbvec_node_ptr_->ref(); |
| |
| result = binary_node<T>::branch_[1].first->value(); |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| rebasevector_celem_node<T>* rbvec_node_ptr_; |
| }; |
| |
| template <typename T> |
| class assignment_vec_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| assignment_vec_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec_node_ptr_(0) |
| { |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); |
| vds() = vec_node_ptr_->vds(); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (vec_node_ptr_) |
| { |
| const T v = binary_node<T>::branch_[1].first->value(); |
| |
| T* vec = vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec + lud.upper_bound; |
| |
| while (vec < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec[N] = v; \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec += lud.batch_size; |
| } |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : *vec++ = v; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return vec_node_ptr_->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return vec_node_ptr_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return vec_node_ptr_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvalass; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node<T>* vec_node_ptr_; |
| vds_t vds_; |
| }; |
| |
| template <typename T> |
| class assignment_vecvec_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| assignment_vecvec_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec0_node_ptr_(0), |
| vec1_node_ptr_(0), |
| initialised_(false), |
| src_is_ivec_(false) |
| { |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); |
| vds() = vec0_node_ptr_->vds(); |
| } |
| |
| if (is_vector_node(binary_node<T>::branch_[1].first)) |
| { |
| vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first); |
| vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[1].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) |
| { |
| vec1_node_ptr_ = vi->vec(); |
| |
| if (!vi->side_effect()) |
| { |
| vi->vds() = vds(); |
| src_is_ivec_ = true; |
| } |
| else |
| vds_t::match_sizes(vds(),vi->vds()); |
| } |
| } |
| |
| initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[1].first->value(); |
| |
| if (src_is_ivec_) |
| return vec0_node_ptr_->value(); |
| |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vec1_node_ptr_->vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec0 + lud.upper_bound; |
| |
| while (vec0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec0[N] = vec1[N]; \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| } |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : *vec0++ = *vec1++; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return vec0_node_ptr_->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return vec0_node_ptr_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return vec0_node_ptr_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvecass; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node<T>* vec0_node_ptr_; |
| vector_node<T>* vec1_node_ptr_; |
| bool initialised_; |
| bool src_is_ivec_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_op_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| var_node_ptr_(0) |
| { |
| if (is_variable_node(binary_node<T>::branch_[0].first)) |
| { |
| var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (var_node_ptr_) |
| { |
| T& v = var_node_ptr_->ref(); |
| v = Operation::process(v,binary_node<T>::branch_[1].first->value()); |
| |
| return v; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| variable_node<T>* var_node_ptr_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_vec_elem_op_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_vec_elem_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec_node_ptr_(0) |
| { |
| if (is_vector_elem_node(binary_node<T>::branch_[0].first)) |
| { |
| vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (vec_node_ptr_) |
| { |
| T& v = vec_node_ptr_->ref(); |
| v = Operation::process(v,binary_node<T>::branch_[1].first->value()); |
| |
| return v; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| vector_elem_node<T>* vec_node_ptr_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_rebasevec_elem_op_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_rebasevec_elem_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| rbvec_node_ptr_(0) |
| { |
| if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) |
| { |
| rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (rbvec_node_ptr_) |
| { |
| T& v = rbvec_node_ptr_->ref(); |
| v = Operation::process(v,binary_node<T>::branch_[1].first->value()); |
| |
| return v; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| rebasevector_elem_node<T>* rbvec_node_ptr_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_rebasevec_celem_op_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| assignment_rebasevec_celem_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| rbvec_node_ptr_(0) |
| { |
| if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) |
| { |
| rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (rbvec_node_ptr_) |
| { |
| T& v = rbvec_node_ptr_->ref(); |
| v = Operation::process(v,binary_node<T>::branch_[1].first->value()); |
| |
| return v; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| private: |
| |
| rebasevector_celem_node<T>* rbvec_node_ptr_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_vec_op_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| assignment_vec_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec_node_ptr_(0) |
| { |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); |
| vds() = vec_node_ptr_->vds(); |
| } |
| } |
| |
| inline T value() const |
| { |
| if (vec_node_ptr_) |
| { |
| const T v = binary_node<T>::branch_[1].first->value(); |
| |
| T* vec = vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec + lud.upper_bound; |
| |
| while (vec < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| Operation::assign(vec[N],v); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec += lud.batch_size; |
| } |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : Operation::assign(*vec++,v); \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return vec_node_ptr_->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return vec_node_ptr_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return vec_node_ptr_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecopvalass; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| bool side_effect() const |
| { |
| return true; |
| } |
| |
| private: |
| |
| vector_node<T>* vec_node_ptr_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class assignment_vecvec_op_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| assignment_vecvec_op_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec0_node_ptr_(0), |
| vec1_node_ptr_(0), |
| initialised_(false) |
| { |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); |
| vds() = vec0_node_ptr_->vds(); |
| } |
| |
| if (is_vector_node(binary_node<T>::branch_[1].first)) |
| { |
| vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first); |
| vec1_node_ptr_->vds() = vds(); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[1].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) |
| { |
| vec1_node_ptr_ = vi->vec(); |
| vec1_node_ptr_->vds() = vds(); |
| } |
| else |
| vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); |
| } |
| |
| initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vec1_node_ptr_->vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec0 + lud.upper_bound; |
| |
| while (vec0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec0[N] = Operation::process(vec0[N],vec1[N]); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { vec0[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return vec0_node_ptr_->value(); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return vec0_node_ptr_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return vec0_node_ptr_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecopvecass; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| bool side_effect() const |
| { |
| return true; |
| } |
| |
| private: |
| |
| vector_node<T>* vec0_node_ptr_; |
| vector_node<T>* vec1_node_ptr_; |
| bool initialised_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class vec_binop_vecvec_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vector_holder<T>* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| vec_binop_vecvec_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec0_node_ptr_(0), |
| vec1_node_ptr_(0), |
| temp_ (0), |
| temp_vec_node_(0), |
| initialised_(false) |
| { |
| bool v0_is_ivec = false; |
| bool v1_is_ivec = false; |
| |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[0].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) |
| { |
| vec0_node_ptr_ = vi->vec(); |
| v0_is_ivec = true; |
| } |
| } |
| |
| if (is_vector_node(binary_node<T>::branch_[1].first)) |
| { |
| vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[1].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) |
| { |
| vec1_node_ptr_ = vi->vec(); |
| v1_is_ivec = true; |
| } |
| } |
| |
| if (vec0_node_ptr_ && vec1_node_ptr_) |
| { |
| vector_holder<T>& vec0 = vec0_node_ptr_->vec_holder(); |
| vector_holder<T>& vec1 = vec1_node_ptr_->vec_holder(); |
| |
| if (v0_is_ivec && (vec0.size() <= vec1.size())) |
| vds_ = vds_t(vec0_node_ptr_->vds()); |
| else if (v1_is_ivec && (vec1.size() <= vec0.size())) |
| vds_ = vds_t(vec1_node_ptr_->vds()); |
| else |
| vds_ = vds_t(std::min(vec0.size(),vec1.size())); |
| |
| temp_ = new vector_holder<T>(vds().data(),vds().size()); |
| temp_vec_node_ = new vector_node<T> (vds(),temp_); |
| |
| initialised_ = true; |
| } |
| } |
| |
| ~vec_binop_vecvec_node() |
| { |
| delete temp_; |
| delete temp_vec_node_; |
| } |
| |
| inline T value() const |
| { |
| if (initialised_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vec1_node_ptr_->vds().data(); |
| T* vec2 = vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec2 + lud.upper_bound; |
| |
| while (vec2 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec2[N] = Operation::process(vec0[N],vec1[N]); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| vec2 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { vec2[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (vds().data())[0]; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return temp_vec_node_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return temp_vec_node_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvecarith; |
| } |
| |
| std::size_t size() const |
| { |
| return vds_.size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node_ptr vec0_node_ptr_; |
| vector_node_ptr vec1_node_ptr_; |
| vector_holder_ptr temp_; |
| vector_node_ptr temp_vec_node_; |
| bool initialised_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class vec_binop_vecval_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vector_holder<T>* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| vec_binop_vecval_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec0_node_ptr_(0), |
| temp_ (0), |
| temp_vec_node_(0) |
| { |
| bool v0_is_ivec = false; |
| |
| if (is_vector_node(binary_node<T>::branch_[0].first)) |
| { |
| vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[0].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) |
| { |
| vec0_node_ptr_ = vi->vec(); |
| v0_is_ivec = true; |
| } |
| } |
| |
| if (vec0_node_ptr_) |
| { |
| if (v0_is_ivec) |
| vds() = vec0_node_ptr_->vds(); |
| else |
| vds() = vds_t(vec0_node_ptr_->size()); |
| |
| temp_ = new vector_holder<T>(vds()); |
| temp_vec_node_ = new vector_node<T> (vds(),temp_); |
| } |
| } |
| |
| ~vec_binop_vecval_node() |
| { |
| delete temp_; |
| delete temp_vec_node_; |
| } |
| |
| inline T value() const |
| { |
| if (vec0_node_ptr_) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| const T v = binary_node<T>::branch_[1].first->value(); |
| |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec0 + lud.upper_bound; |
| |
| while (vec0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec1[N] = Operation::process(vec0[N],v); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { vec1[i] = Operation::process(vec0[i],v); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (vds().data())[0]; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return temp_vec_node_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return temp_vec_node_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvalarith; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node_ptr vec0_node_ptr_; |
| vector_holder_ptr temp_; |
| vector_node_ptr temp_vec_node_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class vec_binop_valvec_node : public binary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vector_holder<T>* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| vec_binop_valvec_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| vec1_node_ptr_(0), |
| temp_ (0), |
| temp_vec_node_(0) |
| { |
| bool v1_is_ivec = false; |
| |
| if (is_vector_node(binary_node<T>::branch_[1].first)) |
| { |
| vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first); |
| } |
| else if (is_ivector_node(binary_node<T>::branch_[1].first)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) |
| { |
| vec1_node_ptr_ = vi->vec(); |
| v1_is_ivec = true; |
| } |
| } |
| |
| if (vec1_node_ptr_) |
| { |
| if (v1_is_ivec) |
| vds() = vec1_node_ptr_->vds(); |
| else |
| vds() = vds_t(vec1_node_ptr_->size()); |
| |
| temp_ = new vector_holder<T>(vds()); |
| temp_vec_node_ = new vector_node<T> (vds(),temp_); |
| } |
| } |
| |
| ~vec_binop_valvec_node() |
| { |
| delete temp_; |
| delete temp_vec_node_; |
| } |
| |
| inline T value() const |
| { |
| if (vec1_node_ptr_) |
| { |
| const T v = binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| T* vec0 = vds().data(); |
| T* vec1 = vec1_node_ptr_->vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec0 + lud.upper_bound; |
| |
| while (vec0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec0[N] = Operation::process(v,vec1[N]); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { vec0[i] = Operation::process(v,vec1[i]); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (vds().data())[0]; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return temp_vec_node_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return temp_vec_node_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecvalarith; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node_ptr vec1_node_ptr_; |
| vector_holder_ptr temp_; |
| vector_node_ptr temp_vec_node_; |
| vds_t vds_; |
| }; |
| |
| template <typename T, typename Operation> |
| class unary_vector_node : public unary_node <T>, |
| public vector_interface<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef vector_node<T>* vector_node_ptr; |
| typedef vector_holder<T>* vector_holder_ptr; |
| typedef vec_data_store<T> vds_t; |
| |
| unary_vector_node(const operator_type& opr, expression_ptr branch0) |
| : unary_node<T>(opr,branch0), |
| vec0_node_ptr_(0), |
| temp_ (0), |
| temp_vec_node_(0) |
| { |
| bool vec0_is_ivec = false; |
| |
| if (is_vector_node(unary_node<T>::branch_)) |
| { |
| vec0_node_ptr_ = static_cast<vector_node_ptr>(unary_node<T>::branch_); |
| } |
| else if (is_ivector_node(unary_node<T>::branch_)) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 != (vi = dynamic_cast<vector_interface<T>*>(unary_node<T>::branch_))) |
| { |
| vec0_node_ptr_ = vi->vec(); |
| vec0_is_ivec = true; |
| } |
| } |
| |
| if (vec0_node_ptr_) |
| { |
| if (vec0_is_ivec) |
| vds_ = vec0_node_ptr_->vds(); |
| else |
| vds_ = vds_t(vec0_node_ptr_->size()); |
| |
| temp_ = new vector_holder<T>(vds()); |
| temp_vec_node_ = new vector_node<T> (vds(),temp_); |
| } |
| } |
| |
| ~unary_vector_node() |
| { |
| delete temp_; |
| delete temp_vec_node_; |
| } |
| |
| inline T value() const |
| { |
| unary_node<T>::branch_->value(); |
| |
| if (vec0_node_ptr_) |
| { |
| T* vec0 = vec0_node_ptr_->vds().data(); |
| T* vec1 = vds().data(); |
| |
| loop_unroll::details lud(size()); |
| const T* upper_bound = vec0 + lud.upper_bound; |
| |
| while (vec0 < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| vec1[N] = Operation::process(vec0[N]); \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec0 += lud.batch_size; |
| vec1 += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (vds().data())[0]; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| vector_node_ptr vec() const |
| { |
| return temp_vec_node_; |
| } |
| |
| vector_node_ptr vec() |
| { |
| return temp_vec_node_; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vecunaryop; |
| } |
| |
| std::size_t size() const |
| { |
| return vds().size(); |
| } |
| |
| vds_t& vds() |
| { |
| return vds_; |
| } |
| |
| const vds_t& vds() const |
| { |
| return vds_; |
| } |
| |
| private: |
| |
| vector_node_ptr vec0_node_ptr_; |
| vector_holder_ptr temp_; |
| vector_node_ptr temp_vec_node_; |
| vds_t vds_; |
| }; |
| |
| template <typename T> |
| class scand_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| scand_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1) |
| {} |
| |
| inline T value() const |
| { |
| return ( |
| std::not_equal_to<T>() |
| (T(0),binary_node<T>::branch_[0].first->value()) && |
| std::not_equal_to<T>() |
| (T(0),binary_node<T>::branch_[1].first->value()) |
| ) ? T(1) : T(0); |
| } |
| }; |
| |
| template <typename T> |
| class scor_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| scor_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1) |
| {} |
| |
| inline T value() const |
| { |
| return ( |
| std::not_equal_to<T>() |
| (T(0),binary_node<T>::branch_[0].first->value()) || |
| std::not_equal_to<T>() |
| (T(0),binary_node<T>::branch_[1].first->value()) |
| ) ? T(1) : T(0); |
| } |
| }; |
| |
| template <typename T, typename IFunction, std::size_t N> |
| class function_N_node : public expression_node<T> |
| { |
| public: |
| |
| // Function of N paramters. |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef IFunction ifunction; |
| |
| function_N_node(ifunction* func) |
| : function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0)), |
| parameter_count_(func->param_count) |
| {} |
| |
| ~function_N_node() |
| { |
| cleanup_branches::execute<T,N>(branch_); |
| } |
| |
| template <std::size_t NumBranches> |
| bool init_branches(expression_ptr (&b)[NumBranches]) |
| { |
| // Needed for incompetent and broken msvc compiler versions |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable: 4127) |
| #endif |
| if (N != NumBranches) |
| return false; |
| else |
| { |
| 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; |
| } |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } |
| |
| inline bool operator <(const function_N_node<T,IFunction,N>& fn) const |
| { |
| return this < (&fn); |
| } |
| |
| inline T value() const |
| { |
| // Needed for incompetent and broken msvc compiler versions |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable: 4127) |
| #endif |
| if ((0 == function_) || (0 == N)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else |
| { |
| T v[N]; |
| evaluate_branches<T,N>::execute(v,branch_); |
| return invoke<T,N>::execute(*function_,v); |
| } |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } |
| |
| template <typename T_, std::size_t BranchCount> |
| struct evaluate_branches |
| { |
| static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) |
| { |
| for (std::size_t i = 0; i < BranchCount; ++i) |
| { |
| v[i] = b[i].first->value(); |
| } |
| } |
| }; |
| |
| template <typename T_> |
| struct evaluate_branches <T_,5> |
| { |
| static inline void execute(T_ (&v)[5], const branch_t (&b)[5]) |
| { |
| v[0] = b[0].first->value(); |
| v[1] = b[1].first->value(); |
| v[2] = b[2].first->value(); |
| v[3] = b[3].first->value(); |
| v[4] = b[4].first->value(); |
| } |
| }; |
| |
| template <typename T_> |
| struct evaluate_branches <T_,4> |
| { |
| static inline void execute(T_ (&v)[4], const branch_t (&b)[4]) |
| { |
| v[0] = b[0].first->value(); |
| v[1] = b[1].first->value(); |
| v[2] = b[2].first->value(); |
| v[3] = b[3].first->value(); |
| } |
| }; |
| |
| template <typename T_> |
| struct evaluate_branches <T_,3> |
| { |
| static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) |
| { |
| v[0] = b[0].first->value(); |
| v[1] = b[1].first->value(); |
| v[2] = b[2].first->value(); |
| } |
| }; |
| |
| template <typename T_> |
| struct evaluate_branches <T_,2> |
| { |
| static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) |
| { |
| v[0] = b[0].first->value(); |
| v[1] = b[1].first->value(); |
| } |
| }; |
| |
| template <typename T_> |
| struct evaluate_branches <T_,1> |
| { |
| static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) |
| { |
| v[0] = b[0].first->value(); |
| } |
| }; |
| |
| template <typename T_, std::size_t ParamCount> |
| struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits<T_>::quiet_NaN(); } }; |
| |
| template <typename T_> |
| struct invoke<T_,20> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[20]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,19> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[19]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,18> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[18]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,17> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[17]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,16> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[16]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,15> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[15]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,14> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[14]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,13> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[13]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,12> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[12]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,11> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[11]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,10> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[10]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,9> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[9]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,8> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[8]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,7> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[7]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,6> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[6]) |
| { return f(v[0],v[1],v[2],v[3],v[4],v[5]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,5> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[5]) |
| { return f(v[0],v[1],v[2],v[3],v[4]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,4> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[4]) |
| { return f(v[0],v[1],v[2],v[3]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,3> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[3]) |
| { return f(v[0],v[1],v[2]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,2> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[2]) |
| { return f(v[0],v[1]); } |
| }; |
| |
| template <typename T_> |
| struct invoke<T_,1> |
| { |
| static inline T_ execute(ifunction& f, T_ (&v)[1]) |
| { return f(v[0]); } |
| }; |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_function; |
| } |
| |
| private: |
| |
| ifunction* function_; |
| std::size_t parameter_count_; |
| branch_t branch_[N]; |
| }; |
| |
| template <typename T, typename IFunction> |
| class function_N_node<T,IFunction,0> : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef IFunction ifunction; |
| |
| function_N_node(ifunction* func) |
| : function_((0 == func->param_count) ? func : reinterpret_cast<ifunction*>(0)) |
| {} |
| |
| inline bool operator <(const function_N_node<T,IFunction,0>& fn) const |
| { |
| return this < (&fn); |
| } |
| |
| inline T value() const |
| { |
| if (function_) |
| return (*function_)(); |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_function; |
| } |
| |
| private: |
| |
| ifunction* function_; |
| }; |
| |
| template <typename T, typename VarArgFunction> |
| class vararg_function_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| |
| vararg_function_node(VarArgFunction* func, |
| const std::vector<expression_ptr>& arg_list) |
| : function_(func), |
| arg_list_(arg_list) |
| { |
| value_list_.resize(arg_list.size(),std::numeric_limits<T>::quiet_NaN()); |
| } |
| |
| ~vararg_function_node() |
| { |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) |
| { |
| delete arg_list_[i]; |
| arg_list_[i] = 0; |
| } |
| } |
| } |
| |
| inline bool operator <(const vararg_function_node<T,VarArgFunction>& fn) const |
| { |
| return this < (&fn); |
| } |
| |
| inline T value() const |
| { |
| if (function_) |
| { |
| populate_value_list(); |
| return (*function_)(value_list_); |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_vafunction; |
| } |
| |
| private: |
| |
| inline void populate_value_list() const |
| { |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| value_list_[i] = arg_list_[i]->value(); |
| } |
| } |
| |
| VarArgFunction* function_; |
| std::vector<expression_ptr> arg_list_; |
| mutable std::vector<T> value_list_; |
| }; |
| |
| template <typename T, typename GenericFunction> |
| class generic_function_node : public expression_node<T> |
| { |
| public: |
| |
| typedef type_store<T> type_store_t; |
| typedef expression_node<T>* expression_ptr; |
| typedef variable_node<T> variable_node_t; |
| typedef vector_node<T> vector_node_t; |
| typedef variable_node_t* variable_node_ptr_t; |
| typedef vector_node_t* vector_node_ptr_t; |
| typedef range_interface<T> range_interface_t; |
| typedef range_data_type<T> range_data_type_t; |
| typedef range_pack<T> range_t; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef std::pair<void*,std::size_t> void_t; |
| typedef std::vector<T> tmp_vs_t; |
| typedef std::vector<type_store_t> typestore_list_t; |
| typedef std::vector<range_data_type_t> range_list_t; |
| |
| generic_function_node(const std::vector<expression_ptr>& arg_list, |
| GenericFunction* func = (GenericFunction*)(0)) |
| : function_(func), |
| arg_list_(arg_list) |
| {} |
| |
| virtual ~generic_function_node() |
| { |
| cleanup_branches::execute(branch_); |
| } |
| |
| virtual bool init_branches() |
| { |
| expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); |
| typestore_list_ .resize(arg_list_.size(),type_store_t() ); |
| range_list_ .resize(arg_list_.size(),range_data_type_t()); |
| branch_ .resize(arg_list_.size(),branch_t((expression_ptr)0,false)); |
| |
| for (std::size_t i = 0; i < arg_list_.size(); ++i) |
| { |
| type_store_t& ts = typestore_list_[i]; |
| |
| if (0 == arg_list_[i]) |
| return false; |
| else if (is_ivector_node(arg_list_[i])) |
| { |
| vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); |
| |
| if (0 == (vi = dynamic_cast<vector_interface<T>*>(arg_list_[i]))) |
| return false; |
| |
| ts.size = vi->size(); |
| ts.data = vi->vds().data(); |
| ts.type = type_store_t::e_vector; |
| } |
| else if (is_generally_string_node(arg_list_[i])) |
| { |
| string_base_node<T>* sbn = reinterpret_cast<string_base_node<T>*>(0); |
| |
| if (0 == (sbn = dynamic_cast<string_base_node<T>*>(arg_list_[i]))) |
| return false; |
| |
| ts.size = sbn->size(); |
| ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base())); |
| ts.type = type_store_t::e_string; |
| |
| range_list_[i].data = ts.data; |
| range_list_[i].size = ts.size; |
| range_list_[i].type_size = sizeof(char); |
| range_list_[i].str_node = sbn; |
| |
| range_interface_t* ri = reinterpret_cast<range_interface_t*>(0); |
| |
| if (0 == (ri = dynamic_cast<range_interface_t*>(arg_list_[i]))) |
| return false; |
| |
| range_t& rp = ri->range_ref(); |
| |
| if ( |
| rp.const_range() && |
| is_const_string_range_node(arg_list_[i]) |
| ) |
| { |
| ts.size = rp.const_size(); |
| ts.data = static_cast<char*>(ts.data) + rp.n0_c.second; |
| range_list_[i].range = reinterpret_cast<range_t*>(0); |
| } |
| else |
| range_list_[i].range = &(ri->range_ref()); |
| } |
| else if (is_variable_node(arg_list_[i])) |
| { |
| variable_node_ptr_t var = variable_node_ptr_t(0); |
| |
| if (0 == (var = dynamic_cast<variable_node_ptr_t>(arg_list_[i]))) |
| return false; |
| |
| ts.size = 1; |
| ts.data = &var->ref(); |
| ts.type = type_store_t::e_scalar; |
| } |
| else |
| { |
| ts.size = 1; |
| ts.data = reinterpret_cast<void*>(&expr_as_vec1_store_[i]); |
| ts.type = type_store_t::e_scalar; |
| } |
| |
| branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); |
| } |
| |
| return true; |
| } |
| |
| inline bool operator <(const generic_function_node<T,GenericFunction>& fn) const |
| { |
| return this < (&fn); |
| } |
| |
| inline T value() const |
| { |
| if (function_) |
| { |
| if (populate_value_list()) |
| { |
| typedef typename GenericFunction::parameter_list_t parameter_list_t; |
| |
| return (*function_)(parameter_list_t(typestore_list_)); |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_genfunction; |
| } |
| |
| protected: |
| |
| inline virtual bool populate_value_list() const |
| { |
| for (std::size_t i = 0; i < branch_.size(); ++i) |
| { |
| expr_as_vec1_store_[i] = branch_[i].first->value(); |
| } |
| |
| for (std::size_t i = 0; i < branch_.size(); ++i) |
| { |
| range_data_type_t& rdt = range_list_[i]; |
| |
| if (rdt.range) |
| { |
| range_t& rp = (*rdt.range); |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| if (rp(r0,r1,rdt.size)) |
| { |
| type_store_t& ts = typestore_list_[i]; |
| |
| ts.size = rp.cache_size(); |
| |
| if (ts.type == type_store_t::e_string) |
| ts.data = const_cast<char*>(rdt.str_node->base()) + rp.cache.first; |
| else |
| ts.data = static_cast<char*>(rdt.data) + (rp.cache.first * rdt.type_size); |
| } |
| else |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| GenericFunction* function_; |
| mutable typestore_list_t typestore_list_; |
| |
| private: |
| |
| std::vector<expression_ptr> arg_list_; |
| std::vector<branch_t> branch_; |
| mutable tmp_vs_t expr_as_vec1_store_; |
| mutable range_list_t range_list_; |
| }; |
| |
| template <typename T, typename StringFunction> |
| class string_function_node : public generic_function_node<T,StringFunction>, |
| public string_base_node<T>, |
| public range_interface <T> |
| { |
| public: |
| |
| typedef generic_function_node<T,StringFunction> gen_function_t; |
| typedef range_pack<T> range_t; |
| |
| string_function_node(StringFunction* func, |
| const std::vector<typename gen_function_t::expression_ptr>& arg_list) |
| : gen_function_t(arg_list,func) |
| { |
| range_.n0_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.n1_c = std::make_pair<bool,std::size_t>(true,0); |
| range_.cache.first = range_.n0_c.second; |
| range_.cache.second = range_.n1_c.second; |
| } |
| |
| inline bool operator <(const string_function_node<T,StringFunction>& fn) const |
| { |
| return this < (&fn); |
| } |
| |
| inline T value() const |
| { |
| T result = std::numeric_limits<T>::quiet_NaN(); |
| |
| if (gen_function_t::function_) |
| { |
| if (gen_function_t::populate_value_list()) |
| { |
| typedef typename StringFunction::parameter_list_t parameter_list_t; |
| |
| result = (*gen_function_t::function_)(ret_string_, |
| parameter_list_t(gen_function_t::typestore_list_)); |
| |
| range_.n1_c.second = ret_string_.size() - 1; |
| range_.cache.second = range_.n1_c.second; |
| |
| return result; |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strfunction; |
| } |
| |
| std::string str() const |
| { |
| return ret_string_; |
| } |
| |
| const char* base() const |
| { |
| return &ret_string_[0]; |
| } |
| |
| std::size_t size() const |
| { |
| return ret_string_.size(); |
| } |
| |
| range_t& range_ref() |
| { |
| return range_; |
| } |
| |
| const range_t& range_ref() const |
| { |
| return range_; |
| } |
| |
| protected: |
| |
| mutable range_t range_; |
| mutable std::string ret_string_; |
| }; |
| |
| template <typename T, typename GenericFunction> |
| class multimode_genfunction_node : public generic_function_node<T,GenericFunction> |
| { |
| public: |
| |
| typedef generic_function_node<T,GenericFunction> gen_function_t; |
| typedef range_pack<T> range_t; |
| |
| multimode_genfunction_node(GenericFunction* func, |
| const std::size_t& param_seq_index, |
| const std::vector<typename gen_function_t::expression_ptr>& arg_list) |
| : gen_function_t(arg_list,func), |
| param_seq_index_(param_seq_index) |
| {} |
| |
| inline T value() const |
| { |
| T result = std::numeric_limits<T>::quiet_NaN(); |
| |
| if (gen_function_t::function_) |
| { |
| if (gen_function_t::populate_value_list()) |
| { |
| typedef typename GenericFunction::parameter_list_t parameter_list_t; |
| |
| return (*gen_function_t::function_)(param_seq_index_, |
| parameter_list_t(gen_function_t::typestore_list_)); |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_genfunction; |
| } |
| |
| private: |
| |
| std::size_t param_seq_index_; |
| }; |
| |
| template <typename T, typename StringFunction> |
| class multimode_strfunction_node : public string_function_node<T,StringFunction> |
| { |
| public: |
| |
| typedef string_function_node<T,StringFunction> str_function_t; |
| typedef range_pack<T> range_t; |
| |
| multimode_strfunction_node(StringFunction* func, |
| const std::size_t& param_seq_index, |
| const std::vector<typename str_function_t::expression_ptr>& arg_list) |
| : str_function_t(func,arg_list), |
| param_seq_index_(param_seq_index) |
| {} |
| |
| inline T value() const |
| { |
| T result = std::numeric_limits<T>::quiet_NaN(); |
| |
| if (str_function_t::function_) |
| { |
| if (str_function_t::populate_value_list()) |
| { |
| typedef typename StringFunction::parameter_list_t parameter_list_t; |
| |
| result = (*str_function_t::function_)(param_seq_index_, |
| str_function_t::ret_string_, |
| parameter_list_t(str_function_t::typestore_list_)); |
| |
| str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; |
| str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; |
| |
| return result; |
| } |
| } |
| |
| return result; |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_strfunction; |
| } |
| |
| private: |
| |
| std::size_t param_seq_index_; |
| }; |
| |
| class return_exception |
| {}; |
| |
| template <typename T> |
| class null_igenfunc |
| { |
| public: |
| |
| virtual ~null_igenfunc() |
| {} |
| |
| typedef type_store<T> generic_type; |
| typedef typename generic_type::parameter_list parameter_list_t; |
| |
| inline virtual T operator()(parameter_list_t) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| }; |
| |
| template <typename T> |
| class return_node : public generic_function_node<T,null_igenfunc<T> > |
| { |
| public: |
| |
| typedef null_igenfunc<T> igeneric_function_t; |
| typedef igeneric_function_t* igeneric_function_ptr; |
| typedef generic_function_node<T,igeneric_function_t> gen_function_t; |
| typedef results_context<T> results_context_t; |
| |
| return_node(const std::vector<typename gen_function_t::expression_ptr>& arg_list, |
| results_context_t& rc) |
| : gen_function_t (arg_list), |
| results_context_(&rc) |
| {} |
| |
| inline T value() const |
| { |
| if ( |
| (0 != results_context_) && |
| gen_function_t::populate_value_list() |
| ) |
| { |
| typedef typename type_store<T>::parameter_list parameter_list_t; |
| |
| results_context_-> |
| assign(parameter_list_t(gen_function_t::typestore_list_)); |
| |
| throw return_exception(); |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_return; |
| } |
| |
| private: |
| |
| results_context_t* results_context_; |
| }; |
| |
| template <typename T> |
| class return_envelope_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef results_context<T> results_context_t; |
| |
| return_envelope_node(expression_ptr body, results_context_t& rc) |
| : results_context_(&rc), |
| return_invoked_ (false), |
| body_ (body), |
| body_deletable_ (branch_deletable(body_)) |
| {} |
| |
| ~return_envelope_node() |
| { |
| if (body_ && body_deletable_) |
| { |
| delete body_; |
| } |
| } |
| |
| inline T value() const |
| { |
| try |
| { |
| return_invoked_ = false; |
| results_context_->clear(); |
| |
| return body_->value(); |
| } |
| catch(const return_exception&) |
| { |
| return_invoked_ = true; |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_retenv; |
| } |
| |
| inline bool* retinvk_ptr() |
| { |
| return &return_invoked_; |
| } |
| |
| private: |
| |
| results_context_t* results_context_; |
| mutable bool return_invoked_; |
| expression_ptr body_; |
| bool body_deletable_; |
| }; |
| |
| #define exprtk_define_unary_op(OpName) \ |
| template <typename T> \ |
| struct OpName##_op \ |
| { \ |
| typedef typename functor_t<T>::Type Type; \ |
| typedef typename expression_node<T>::node_type node_t; \ |
| \ |
| static inline T process(Type v) \ |
| { \ |
| return numeric:: OpName (v); \ |
| } \ |
| \ |
| static inline node_t type() \ |
| { \ |
| return expression_node<T>::e_##OpName; \ |
| } \ |
| \ |
| static inline details::operator_type operation() \ |
| { \ |
| return details::e_##OpName; \ |
| } \ |
| }; \ |
| |
| exprtk_define_unary_op(abs ) |
| exprtk_define_unary_op(acos ) |
| exprtk_define_unary_op(acosh) |
| exprtk_define_unary_op(asin ) |
| exprtk_define_unary_op(asinh) |
| exprtk_define_unary_op(atan ) |
| exprtk_define_unary_op(atanh) |
| exprtk_define_unary_op(ceil ) |
| exprtk_define_unary_op(cos ) |
| exprtk_define_unary_op(cosh ) |
| exprtk_define_unary_op(cot ) |
| exprtk_define_unary_op(csc ) |
| exprtk_define_unary_op(d2g ) |
| exprtk_define_unary_op(d2r ) |
| exprtk_define_unary_op(erf ) |
| exprtk_define_unary_op(erfc ) |
| exprtk_define_unary_op(exp ) |
| exprtk_define_unary_op(expm1) |
| exprtk_define_unary_op(floor) |
| exprtk_define_unary_op(frac ) |
| exprtk_define_unary_op(g2d ) |
| exprtk_define_unary_op(log ) |
| exprtk_define_unary_op(log10) |
| exprtk_define_unary_op(log2 ) |
| exprtk_define_unary_op(log1p) |
| exprtk_define_unary_op(ncdf ) |
| exprtk_define_unary_op(neg ) |
| exprtk_define_unary_op(notl ) |
| exprtk_define_unary_op(pos ) |
| exprtk_define_unary_op(r2d ) |
| exprtk_define_unary_op(round) |
| exprtk_define_unary_op(sec ) |
| exprtk_define_unary_op(sgn ) |
| exprtk_define_unary_op(sin ) |
| exprtk_define_unary_op(sinc ) |
| exprtk_define_unary_op(sinh ) |
| exprtk_define_unary_op(sqrt ) |
| exprtk_define_unary_op(tan ) |
| exprtk_define_unary_op(tanh ) |
| exprtk_define_unary_op(trunc) |
| #undef exprtk_define_unary_op |
| |
| template <typename T> |
| struct opr_base |
| { |
| typedef typename details::functor_t<T>::Type Type; |
| typedef typename details::functor_t<T>::RefType RefType; |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::qfunc_t quaternary_functor_t; |
| typedef typename functor_t::tfunc_t trinary_functor_t; |
| typedef typename functor_t::bfunc_t binary_functor_t; |
| typedef typename functor_t::ufunc_t unary_functor_t; |
| }; |
| |
| template <typename T> |
| struct add_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return t1 + t2; } |
| static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } |
| static inline void assign(RefType t1, Type t2) { t1 += t2; } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_add; } |
| static inline details::operator_type operation() { return details::e_add; } |
| }; |
| |
| template <typename T> |
| struct mul_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return t1 * t2; } |
| static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } |
| static inline void assign(RefType t1, Type t2) { t1 *= t2; } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mul; } |
| static inline details::operator_type operation() { return details::e_mul; } |
| }; |
| |
| template <typename T> |
| struct sub_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return t1 - t2; } |
| static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } |
| static inline void assign(RefType t1, Type t2) { t1 -= t2; } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_sub; } |
| static inline details::operator_type operation() { return details::e_sub; } |
| }; |
| |
| template <typename T> |
| struct div_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return t1 / t2; } |
| static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } |
| static inline void assign(RefType t1, Type t2) { t1 /= t2; } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_div; } |
| static inline details::operator_type operation() { return details::e_div; } |
| }; |
| |
| template <typename T> |
| struct mod_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return numeric::modulus<T>(t1,t2); } |
| static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus<T>(t1,t2); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mod; } |
| static inline details::operator_type operation() { return details::e_mod; } |
| }; |
| |
| template <typename T> |
| struct pow_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| typedef typename opr_base<T>::RefType RefType; |
| static inline T process(Type t1, Type t2) { return numeric::pow<T>(t1,t2); } |
| static inline void assign(RefType t1, Type t2) { t1 = numeric::pow<T>(t1,t2); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_pow; } |
| static inline details::operator_type operation() { return details::e_pow; } |
| }; |
| |
| template <typename T> |
| struct lt_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type 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<T>::node_type type() { return expression_node<T>::e_lt; } |
| static inline details::operator_type operation() { return details::e_lt; } |
| }; |
| |
| template <typename T> |
| struct lte_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type 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<T>::node_type type() { return expression_node<T>::e_lte; } |
| static inline details::operator_type operation() { return details::e_lte; } |
| }; |
| |
| template <typename T> |
| struct gt_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type 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<T>::node_type type() { return expression_node<T>::e_gt; } |
| static inline details::operator_type operation() { return details::e_gt; } |
| }; |
| |
| template <typename T> |
| struct gte_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type 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<T>::node_type type() { return expression_node<T>::e_gte; } |
| static inline details::operator_type operation() { return details::e_gte; } |
| }; |
| |
| template <typename T> |
| struct eq_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (std::equal_to<T>()(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<T>::node_type type() { return expression_node<T>::e_eq; } |
| static inline details::operator_type operation() { return details::e_eq; } |
| }; |
| |
| template <typename T> |
| struct equal_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (numeric::equal<T>(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<T>::node_type type() { return expression_node<T>::e_eq; } |
| static inline details::operator_type operation() { return details::e_equal; } |
| }; |
| |
| template <typename T> |
| struct ne_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (std::not_equal_to<T>()(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<T>::node_type type() { return expression_node<T>::e_ne; } |
| static inline details::operator_type operation() { return details::e_ne; } |
| }; |
| |
| template <typename T> |
| struct and_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_and; } |
| static inline details::operator_type operation() { return details::e_and; } |
| }; |
| |
| template <typename T> |
| struct nand_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nand; } |
| static inline details::operator_type operation() { return details::e_nand; } |
| }; |
| |
| template <typename T> |
| struct or_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_or; } |
| static inline details::operator_type operation() { return details::e_or; } |
| }; |
| |
| template <typename T> |
| struct nor_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } |
| static inline details::operator_type operation() { return details::e_nor; } |
| }; |
| |
| template <typename T> |
| struct xor_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return numeric::xor_opr<T>(t1,t2); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } |
| static inline details::operator_type operation() { return details::e_xor; } |
| }; |
| |
| template <typename T> |
| struct xnor_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(Type t1, Type t2) { return numeric::xnor_opr<T>(t1,t2); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } |
| static inline details::operator_type operation() { return details::e_xnor; } |
| }; |
| |
| template <typename T> |
| struct in_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } |
| static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_in; } |
| static inline details::operator_type operation() { return details::e_in; } |
| }; |
| |
| template <typename T> |
| struct like_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } |
| static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_like; } |
| static inline details::operator_type operation() { return details::e_like; } |
| }; |
| |
| template <typename T> |
| struct ilike_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } |
| static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ilike; } |
| static inline details::operator_type operation() { return details::e_ilike; } |
| }; |
| |
| template <typename T> |
| struct inrange_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } |
| static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) |
| { |
| return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); |
| } |
| static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_inranges; } |
| static inline details::operator_type operation() { return details::e_inrange; } |
| }; |
| |
| template <typename T> |
| inline T value(details::expression_node<T>* n) |
| { |
| return n->value(); |
| } |
| |
| template <typename T> |
| inline T value(T* t) |
| { |
| return (*t); |
| } |
| |
| template <typename T> |
| struct vararg_add_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return T(0); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| T result = T(0); |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| result += value(arg_list[i]); |
| } |
| |
| return result; |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) + value(arg_list[1]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) + value(arg_list[1]) + |
| value(arg_list[2]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) + value(arg_list[1]) + |
| value(arg_list[2]) + value(arg_list[3]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) + value(arg_list[1]) + |
| value(arg_list[2]) + value(arg_list[3]) + |
| value(arg_list[4]); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_mul_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return T(0); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| T result = T(value(arg_list[0])); |
| |
| for (std::size_t i = 1; i < arg_list.size(); ++i) |
| { |
| result *= value(arg_list[i]); |
| } |
| |
| return result; |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) * value(arg_list[1]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) * value(arg_list[1]) * |
| value(arg_list[2]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) * value(arg_list[1]) * |
| value(arg_list[2]) * value(arg_list[3]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return value(arg_list[0]) * value(arg_list[1]) * |
| value(arg_list[2]) * value(arg_list[3]) * |
| value(arg_list[4]); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_avg_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return T(0); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : return vararg_add_op<T>::process(arg_list) / arg_list.size(); |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return (value(arg_list[0]) + value(arg_list[1])) / T(2); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return (value(arg_list[0]) + value(arg_list[1]) + |
| value(arg_list[2]) + value(arg_list[3])) / T(4); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return (value(arg_list[0]) + value(arg_list[1]) + |
| value(arg_list[2]) + value(arg_list[3]) + |
| value(arg_list[4])) / T(5); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_min_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return T(0); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| T result = T(value(arg_list[0])); |
| |
| for (std::size_t i = 1; i < arg_list.size(); ++i) |
| { |
| const T v = value(arg_list[i]); |
| |
| if (v < result) |
| result = v; |
| } |
| |
| return result; |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return std::min<T>(value(arg_list[0]),value(arg_list[1])); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return std::min<T>(std::min<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return std::min<T>( |
| std::min<T>(value(arg_list[0]),value(arg_list[1])), |
| std::min<T>(value(arg_list[2]),value(arg_list[3]))); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return std::min<T>( |
| std::min<T>(std::min<T>(value(arg_list[0]),value(arg_list[1])), |
| std::min<T>(value(arg_list[2]),value(arg_list[3]))), |
| value(arg_list[4])); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_max_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return T(0); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| T result = T(value(arg_list[0])); |
| |
| for (std::size_t i = 1; i < arg_list.size(); ++i) |
| { |
| const T v = value(arg_list[i]); |
| |
| if (v > result) |
| result = v; |
| } |
| |
| return result; |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return std::max<T>(value(arg_list[0]),value(arg_list[1])); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return std::max<T>(std::max<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return std::max<T>( |
| std::max<T>(value(arg_list[0]),value(arg_list[1])), |
| std::max<T>(value(arg_list[2]),value(arg_list[3]))); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return std::max<T>( |
| std::max<T>(std::max<T>(value(arg_list[0]),value(arg_list[1])), |
| std::max<T>(value(arg_list[2]),value(arg_list[3]))), |
| value(arg_list[4])); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_mand_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (std::equal_to<T>()(T(0),value(arg_list[i]))) |
| return T(0); |
| } |
| |
| return T(1); |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return std::not_equal_to<T>() |
| (T(0),value(arg_list[0])) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[3])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[3])) && |
| std::not_equal_to<T>()(T(0),value(arg_list[4])) |
| ) ? T(1) : T(0); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_mor_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| default : |
| { |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (std::not_equal_to<T>()(T(0),value(arg_list[i]))) |
| return T(1); |
| } |
| |
| return T(0); |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return std::not_equal_to<T>() |
| (T(0),value(arg_list[0])) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[3])) |
| ) ? T(1) : T(0); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| return ( |
| std::not_equal_to<T>()(T(0),value(arg_list[0])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[1])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[2])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[3])) || |
| std::not_equal_to<T>()(T(0),value(arg_list[4])) |
| ) ? T(1) : T(0); |
| } |
| }; |
| |
| template <typename T> |
| struct vararg_multi_op : public opr_base<T> |
| { |
| typedef typename opr_base<T>::Type Type; |
| |
| template <typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| static inline T process(const Sequence<Type,Allocator>& arg_list) |
| { |
| switch (arg_list.size()) |
| { |
| case 0 : return std::numeric_limits<T>::quiet_NaN(); |
| case 1 : return process_1(arg_list); |
| case 2 : return process_2(arg_list); |
| case 3 : return process_3(arg_list); |
| case 4 : return process_4(arg_list); |
| case 5 : return process_5(arg_list); |
| case 6 : return process_6(arg_list); |
| case 7 : return process_7(arg_list); |
| case 8 : return process_8(arg_list); |
| default : |
| { |
| for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) |
| { |
| value(arg_list[i]); |
| } |
| |
| return value(arg_list.back()); |
| } |
| } |
| } |
| |
| template <typename Sequence> |
| static inline T process_1(const Sequence& arg_list) |
| { |
| return value(arg_list[0]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_2(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| return value(arg_list[1]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_3(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| return value(arg_list[2]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_4(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| value(arg_list[2]); |
| return value(arg_list[3]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_5(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| value(arg_list[2]); |
| value(arg_list[3]); |
| return value(arg_list[4]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_6(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| value(arg_list[2]); |
| value(arg_list[3]); |
| value(arg_list[4]); |
| return value(arg_list[5]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_7(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| value(arg_list[2]); |
| value(arg_list[3]); |
| value(arg_list[4]); |
| value(arg_list[5]); |
| return value(arg_list[6]); |
| } |
| |
| template <typename Sequence> |
| static inline T process_8(const Sequence& arg_list) |
| { |
| value(arg_list[0]); |
| value(arg_list[1]); |
| value(arg_list[2]); |
| value(arg_list[3]); |
| value(arg_list[4]); |
| value(arg_list[5]); |
| value(arg_list[6]); |
| return value(arg_list[7]); |
| } |
| }; |
| |
| template <typename T> |
| struct vec_add_op |
| { |
| typedef vector_interface<T>* ivector_ptr; |
| |
| static inline T process(const ivector_ptr v) |
| { |
| const T* vec = v->vec()->vds().data(); |
| const std::size_t vec_size = v->vec()->vds().size(); |
| |
| loop_unroll::details lud(vec_size); |
| |
| if (vec_size <= static_cast<std::size_t>(lud.batch_size)) |
| { |
| T result = T(0); |
| int i = 0; |
| |
| switch (vec_size) |
| { |
| #define case_stmt(N) \ |
| case N : result += vec[i++]; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(16) case_stmt(15) |
| case_stmt(14) case_stmt(13) |
| case_stmt(12) case_stmt(11) |
| case_stmt(10) case_stmt( 9) |
| case_stmt( 8) case_stmt( 7) |
| case_stmt( 6) case_stmt( 5) |
| #endif |
| case_stmt( 4) case_stmt( 3) |
| case_stmt( 2) case_stmt( 1) |
| } |
| |
| #undef case_stmt |
| |
| return result; |
| } |
| |
| T r[] = { |
| T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), |
| T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) |
| }; |
| |
| const T* upper_bound = vec + lud.upper_bound; |
| |
| while (vec < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| r[N] += vec[N]; \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : r[0] += vec[i++]; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) |
| #ifndef exprtk_disable_superscalar_unroll |
| + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) |
| + (r[ 8] + r[ 9] + r[10] + r[11]) |
| + (r[12] + r[13] + r[14] + r[15]) |
| #endif |
| ; |
| } |
| }; |
| |
| template <typename T> |
| struct vec_mul_op |
| { |
| typedef vector_interface<T>* ivector_ptr; |
| |
| static inline T process(const ivector_ptr v) |
| { |
| const T* vec = v->vec()->vds().data(); |
| const std::size_t vec_size = v->vec()->vds().size(); |
| |
| loop_unroll::details lud(vec_size); |
| |
| if (vec_size <= static_cast<std::size_t>(lud.batch_size)) |
| { |
| T result = T(1); |
| int i = 0; |
| |
| switch (vec_size) |
| { |
| #define case_stmt(N) \ |
| case N : result *= vec[i++]; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(16) case_stmt(15) |
| case_stmt(14) case_stmt(13) |
| case_stmt(12) case_stmt(11) |
| case_stmt(10) case_stmt( 9) |
| case_stmt( 8) case_stmt( 7) |
| case_stmt( 6) case_stmt( 5) |
| #endif |
| case_stmt( 4) case_stmt( 3) |
| case_stmt( 2) case_stmt( 1) |
| } |
| |
| #undef case_stmt |
| |
| return result; |
| } |
| |
| T r[] = { |
| T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), |
| T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) |
| }; |
| |
| const T* upper_bound = vec + lud.upper_bound; |
| |
| while (vec < upper_bound) |
| { |
| #define exprtk_loop(N) \ |
| r[N] *= vec[N]; \ |
| |
| exprtk_loop( 0) exprtk_loop( 1) |
| exprtk_loop( 2) exprtk_loop( 3) |
| #ifndef exprtk_disable_superscalar_unroll |
| exprtk_loop( 4) exprtk_loop( 5) |
| exprtk_loop( 6) exprtk_loop( 7) |
| exprtk_loop( 8) exprtk_loop( 9) |
| exprtk_loop(10) exprtk_loop(11) |
| exprtk_loop(12) exprtk_loop(13) |
| exprtk_loop(14) exprtk_loop(15) |
| #endif |
| |
| vec += lud.batch_size; |
| } |
| |
| int i = 0; |
| |
| switch (lud.remainder) |
| { |
| #define case_stmt(N) \ |
| case N : r[0] *= vec[i++]; \ |
| |
| #ifndef exprtk_disable_superscalar_unroll |
| case_stmt(15) case_stmt(14) |
| case_stmt(13) case_stmt(12) |
| case_stmt(11) case_stmt(10) |
| case_stmt( 9) case_stmt( 8) |
| case_stmt( 7) case_stmt( 6) |
| case_stmt( 5) case_stmt( 4) |
| #endif |
| case_stmt( 3) case_stmt( 2) |
| case_stmt( 1) |
| } |
| |
| #undef exprtk_loop |
| #undef case_stmt |
| |
| return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) |
| #ifndef exprtk_disable_superscalar_unroll |
| + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) |
| + (r[ 8] * r[ 9] * r[10] * r[11]) |
| + (r[12] * r[13] * r[14] * r[15]) |
| #endif |
| ; |
| } |
| }; |
| |
| template <typename T> |
| struct vec_avg_op |
| { |
| typedef vector_interface<T>* ivector_ptr; |
| |
| static inline T process(const ivector_ptr v) |
| { |
| const std::size_t vec_size = v->vec()->vds().size(); |
| |
| return vec_add_op<T>::process(v) / vec_size; |
| } |
| }; |
| |
| template <typename T> |
| struct vec_min_op |
| { |
| typedef vector_interface<T>* ivector_ptr; |
| |
| static inline T process(const ivector_ptr v) |
| { |
| const T* vec = v->vec()->vds().data(); |
| const std::size_t vec_size = v->vec()->vds().size(); |
| |
| T result = vec[0]; |
| |
| for (std::size_t i = 1; i < vec_size; ++i) |
| { |
| T v_i = vec[i]; |
| |
| if (v_i < result) |
| result = v_i; |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <typename T> |
| struct vec_max_op |
| { |
| typedef vector_interface<T>* ivector_ptr; |
| |
| static inline T process(const ivector_ptr v) |
| { |
| const T* vec = v->vec()->vds().data(); |
| const std::size_t vec_size = v->vec()->vds().size(); |
| |
| T result = vec[0]; |
| |
| for (std::size_t i = 1; i < vec_size; ++i) |
| { |
| T v_i = vec[i]; |
| |
| if (v_i > result) |
| result = v_i; |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <typename T> |
| class vov_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~vov_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T& v0() const = 0; |
| |
| virtual const T& v1() const = 0; |
| }; |
| |
| template <typename T> |
| class cov_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~cov_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T c() const = 0; |
| |
| virtual const T& v() const = 0; |
| }; |
| |
| template <typename T> |
| class voc_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~voc_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T c() const = 0; |
| |
| virtual const T& v() const = 0; |
| }; |
| |
| template <typename T> |
| class vob_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~vob_base_node() |
| {} |
| |
| virtual const T& v() const = 0; |
| }; |
| |
| template <typename T> |
| class bov_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~bov_base_node() |
| {} |
| |
| virtual const T& v() const = 0; |
| }; |
| |
| template <typename T> |
| class cob_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~cob_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T c() const = 0; |
| |
| virtual void set_c(const T) = 0; |
| |
| virtual expression_node<T>* move_branch(const std::size_t& index) = 0; |
| }; |
| |
| template <typename T> |
| class boc_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~boc_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T c() const = 0; |
| |
| virtual void set_c(const T) = 0; |
| |
| virtual expression_node<T>* move_branch(const std::size_t& index) = 0; |
| }; |
| |
| template <typename T> |
| class uv_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~uv_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| virtual const T& v() const = 0; |
| }; |
| |
| template <typename T> |
| class sos_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~sos_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| }; |
| |
| template <typename T> |
| class sosos_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~sosos_base_node() |
| {} |
| |
| inline virtual operator_type operation() const |
| { |
| return details::e_default; |
| } |
| }; |
| |
| template <typename T> |
| class T0oT1oT2_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~T0oT1oT2_base_node() |
| {} |
| |
| virtual std::string type_id() const = 0; |
| }; |
| |
| template <typename T> |
| class T0oT1oT2oT3_base_node : public expression_node<T> |
| { |
| public: |
| |
| virtual ~T0oT1oT2oT3_base_node() |
| {} |
| |
| virtual std::string type_id() const = 0; |
| }; |
| |
| template <typename T, typename Operation> |
| class unary_variable_node : public uv_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| explicit unary_variable_node(const T& var) |
| : v_(var) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(v_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T& v() const |
| { |
| return v_; |
| } |
| |
| private: |
| |
| unary_variable_node(unary_variable_node<T,Operation>&); |
| unary_variable_node<T,Operation>& operator=(unary_variable_node<T,Operation>&); |
| |
| const T& v_; |
| }; |
| |
| template <typename T> |
| class uvouv_node : public expression_node<T> |
| { |
| public: |
| |
| // UOpr1(v0) Op UOpr2(v1) |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| typedef typename functor_t::ufunc_t ufunc_t; |
| |
| explicit uvouv_node(const T& var0,const T& var1, |
| ufunc_t uf0, ufunc_t uf1, bfunc_t bf) |
| : v0_(var0), |
| v1_(var1), |
| u0_(uf0), |
| u1_(uf1), |
| f_ (bf) |
| {} |
| |
| inline T value() const |
| { |
| return f_(u0_(v0_),u1_(v1_)); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_uvouv; |
| } |
| |
| inline operator_type operation() const |
| { |
| return details::e_default; |
| } |
| |
| inline const T& v0() |
| { |
| return v0_; |
| } |
| |
| inline const T& v1() |
| { |
| return v1_; |
| } |
| |
| inline ufunc_t u0() |
| { |
| return u0_; |
| } |
| |
| inline ufunc_t u1() |
| { |
| return u1_; |
| } |
| |
| inline ufunc_t f() |
| { |
| return f_; |
| } |
| |
| private: |
| |
| uvouv_node(uvouv_node<T>&); |
| uvouv_node<T>& operator=(uvouv_node<T>&); |
| |
| const T& v0_; |
| const T& v1_; |
| const ufunc_t u0_; |
| const ufunc_t u1_; |
| const bfunc_t f_; |
| }; |
| |
| template <typename T, typename Operation> |
| class unary_branch_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| explicit unary_branch_node(expression_ptr brnch) |
| : branch_(brnch), |
| branch_deletable_(branch_deletable(branch_)) |
| {} |
| |
| ~unary_branch_node() |
| { |
| if (branch_ && branch_deletable_) |
| { |
| delete branch_; |
| branch_ = 0; |
| } |
| } |
| |
| inline T value() const |
| { |
| return Operation::process(branch_->value()); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_; |
| } |
| |
| inline void release() |
| { |
| branch_deletable_ = false; |
| } |
| |
| private: |
| |
| unary_branch_node(unary_branch_node<T,Operation>&); |
| unary_branch_node<T,Operation>& operator=(unary_branch_node<T,Operation>&); |
| |
| expression_ptr branch_; |
| bool branch_deletable_; |
| }; |
| |
| template <typename T> struct is_const { enum {result = 0}; }; |
| template <typename T> struct is_const <const T> { enum {result = 1}; }; |
| template <typename T> struct is_const_ref { enum {result = 0}; }; |
| template <typename T> struct is_const_ref <const T&> { enum {result = 1}; }; |
| template <typename T> struct is_ref { enum {result = 0}; }; |
| template <typename T> struct is_ref<T&> { enum {result = 1}; }; |
| template <typename T> struct is_ref<const T&> { enum {result = 0}; }; |
| |
| template <std::size_t State> |
| struct param_to_str { static std::string result() { static const std::string r("v"); return r; } }; |
| |
| template <> |
| struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } }; |
| |
| #define exprtk_crtype(Type) \ |
| param_to_str<is_const_ref< Type >::result>::result() \ |
| |
| template <typename T> |
| struct T0oT1oT2process |
| { |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| |
| struct mode0 |
| { |
| static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) |
| { |
| // (T0 o0 T1) o1 T2 |
| return bf1(bf0(t0,t1),t2); |
| } |
| |
| template <typename T0, typename T1, typename T2> |
| static inline std::string id() |
| { |
| static const std::string result = "(" + exprtk_crtype(T0) + "o" + |
| exprtk_crtype(T1) + ")o(" + |
| exprtk_crtype(T2) + ")" ; |
| return result; |
| } |
| }; |
| |
| struct mode1 |
| { |
| static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) |
| { |
| // T0 o0 (T1 o1 T2) |
| return bf0(t0,bf1(t1,t2)); |
| } |
| |
| template <typename T0, typename T1, typename T2> |
| static inline std::string id() |
| { |
| static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + |
| exprtk_crtype(T1) + "o" + |
| exprtk_crtype(T2) + ")" ; |
| return result; |
| } |
| }; |
| }; |
| |
| template <typename T> |
| struct T0oT1oT20T3process |
| { |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| |
| struct mode0 |
| { |
| static inline T process(const T& t0, const T& t1, |
| const T& t2, const T& t3, |
| const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) |
| { |
| // (T0 o0 T1) o1 (T2 o2 T3) |
| return bf1(bf0(t0,t1),bf2(t2,t3)); |
| } |
| |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline std::string id() |
| { |
| static const std::string result = "(" + exprtk_crtype(T0) + "o" + |
| exprtk_crtype(T1) + ")o" + |
| "(" + exprtk_crtype(T2) + "o" + |
| exprtk_crtype(T3) + ")" ; |
| return result; |
| } |
| }; |
| |
| struct mode1 |
| { |
| static inline T process(const T& t0, const T& t1, |
| const T& t2, const T& t3, |
| const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) |
| { |
| // (T0 o0 (T1 o1 (T2 o2 T3)) |
| return bf0(t0,bf1(t1,bf2(t2,t3))); |
| } |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline std::string id() |
| { |
| static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + |
| exprtk_crtype(T1) + ")o(" + |
| exprtk_crtype(T2) + "o" + |
| exprtk_crtype(T3) + "))" ; |
| return result; |
| } |
| }; |
| |
| struct mode2 |
| { |
| static inline T process(const T& t0, const T& t1, |
| const T& t2, const T& t3, |
| const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) |
| { |
| // (T0 o0 ((T1 o1 T2) o2 T3) |
| return bf0(t0,bf2(bf1(t1,t2),t3)); |
| } |
| |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline std::string id() |
| { |
| static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + |
| exprtk_crtype(T1) + "o" + |
| exprtk_crtype(T2) + ")o(" + |
| exprtk_crtype(T3) + "))" ; |
| return result; |
| } |
| }; |
| |
| struct mode3 |
| { |
| static inline T process(const T& t0, const T& t1, |
| const T& t2, const T& t3, |
| const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) |
| { |
| // (((T0 o0 T1) o1 T2) o2 T3) |
| return bf2(bf1(bf0(t0,t1),t2),t3); |
| } |
| |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline std::string id() |
| { |
| static const std::string result = "((" + exprtk_crtype(T0) + "o" + |
| exprtk_crtype(T1) + ")o(" + |
| exprtk_crtype(T2) + "))o(" + |
| exprtk_crtype(T3) + ")"; |
| return result; |
| } |
| }; |
| |
| struct mode4 |
| { |
| static inline T process(const T& t0, const T& t1, |
| const T& t2, const T& t3, |
| const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) |
| { |
| // ((T0 o0 (T1 o1 T2)) o2 T3 |
| return bf2(bf0(t0,bf1(t1,t2)),t3); |
| } |
| |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline std::string id() |
| { |
| static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + |
| exprtk_crtype(T1) + "o" + |
| exprtk_crtype(T2) + "))o(" + |
| exprtk_crtype(T3) + ")" ; |
| return result; |
| } |
| }; |
| }; |
| |
| #undef exprtk_crtype |
| |
| template <typename T, typename T0, typename T1> |
| struct nodetype_T0oT1 { static const typename expression_node<T>::node_type result; }; |
| template <typename T, typename T0, typename T1> |
| const typename expression_node<T>::node_type nodetype_T0oT1<T,T0,T1>::result = expression_node<T>::e_none; |
| |
| #define synthesis_node_type_define(T0_,T1_,v_) \ |
| template <typename T, typename T0, typename T1> \ |
| struct nodetype_T0oT1<T,T0_,T1_> { static const typename expression_node<T>::node_type result; }; \ |
| template <typename T, typename T0, typename T1> \ |
| const typename expression_node<T>::node_type nodetype_T0oT1<T,T0_,T1_>::result = expression_node<T>:: v_; \ |
| |
| synthesis_node_type_define(const T0&,const T1&, e_vov) |
| synthesis_node_type_define(const T0&,const T1 , e_voc) |
| synthesis_node_type_define(const T0 ,const T1&, e_cov) |
| synthesis_node_type_define( T0&, T1&,e_none) |
| synthesis_node_type_define(const T0 ,const T1 ,e_none) |
| synthesis_node_type_define( T0&,const T1 ,e_none) |
| synthesis_node_type_define(const T0 , T1&,e_none) |
| synthesis_node_type_define(const T0&, T1&,e_none) |
| synthesis_node_type_define( T0&,const T1&,e_none) |
| #undef synthesis_node_type_define |
| |
| template <typename T, typename T0, typename T1, typename T2> |
| struct nodetype_T0oT1oT2 { static const typename expression_node<T>::node_type result; }; |
| template <typename T, typename T0, typename T1, typename T2> |
| const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0,T1,T2>::result = expression_node<T>::e_none; |
| |
| #define synthesis_node_type_define(T0_,T1_,T2_,v_) \ |
| template <typename T, typename T0, typename T1, typename T2> \ |
| struct nodetype_T0oT1oT2<T,T0_,T1_,T2_> { static const typename expression_node<T>::node_type result; }; \ |
| template <typename T, typename T0, typename T1, typename T2> \ |
| const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0_,T1_,T2_>::result = expression_node<T>:: v_; \ |
| |
| synthesis_node_type_define(const T0&,const T1&,const T2&, e_vovov) |
| synthesis_node_type_define(const T0&,const T1&,const T2 , e_vovoc) |
| synthesis_node_type_define(const T0&,const T1 ,const T2&, e_vocov) |
| synthesis_node_type_define(const T0 ,const T1&,const T2&, e_covov) |
| synthesis_node_type_define(const T0 ,const T1&,const T2 , e_covoc) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2 , e_none ) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2&, e_none ) |
| synthesis_node_type_define(const T0&,const T1 ,const T2 , e_none ) |
| synthesis_node_type_define( T0&, T1&, T2&, e_none ) |
| #undef synthesis_node_type_define |
| |
| template <typename T, typename T0, typename T1, typename T2, typename T3> |
| struct nodetype_T0oT1oT2oT3 { static const typename expression_node<T>::node_type result; }; |
| template <typename T, typename T0, typename T1, typename T2, typename T3> |
| const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result = expression_node<T>::e_none; |
| |
| #define synthesis_node_type_define(T0_,T1_,T2_,T3_,v_) \ |
| template <typename T, typename T0, typename T1, typename T2, typename T3> \ |
| struct nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_> { static const typename expression_node<T>::node_type result; }; \ |
| template <typename T, typename T0, typename T1, typename T2, typename T3> \ |
| const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_>::result = expression_node<T>:: v_; \ |
| |
| synthesis_node_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov) |
| synthesis_node_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc) |
| synthesis_node_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov) |
| synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov) |
| synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov) |
| synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov) |
| synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc) |
| synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc) |
| synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none ) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none ) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none ) |
| synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none ) |
| synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none ) |
| synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none ) |
| synthesis_node_type_define(const T0&,const T1&,const T2 , const T3 ,e_none ) |
| #undef synthesis_node_type_define |
| |
| template <typename T, typename T0, typename T1> |
| class T0oT1 : public expression_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| typedef T value_type; |
| typedef T0oT1<T,T0,T1> node_type; |
| |
| T0oT1(T0 p0, T1 p1, const bfunc_t p2) |
| : t0_(p0), |
| t1_(p1), |
| f_ (p2) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1<T,T0,T1>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return f_(t0_,t1_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline bfunc_t f() const |
| { |
| return f_; |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, |
| T0 p0, T1 p1, |
| bfunc_t p2) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,bfunc_t&>(p0,p1,p2); |
| } |
| |
| private: |
| |
| T0oT1(T0oT1<T,T0,T1>&) {} |
| T0oT1<T,T0,T1>& operator=(T0oT1<T,T0,T1>&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| const bfunc_t f_; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2, typename ProcessMode> |
| class T0oT1oT2 : public T0oT1oT2_base_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| typedef T value_type; |
| typedef T0oT1oT2<T,T0,T1,T2,ProcessMode> node_type; |
| typedef ProcessMode process_mode_t; |
| |
| T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2), |
| f0_(p3), |
| f1_(p4) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return ProcessMode::process(t0_,t1_,t2_,f0_,f1_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline T2 t2() const |
| { |
| return t2_; |
| } |
| |
| bfunc_t f0() const |
| { |
| return f0_; |
| } |
| |
| bfunc_t f1() const |
| { |
| return f1_; |
| } |
| |
| std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return process_mode_t::template id<T0,T1,T2>(); |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2,bfunc_t,bfunc_t>(p0,p1,p2,p3,p4); |
| } |
| |
| private: |
| |
| T0oT1oT2(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| const bfunc_t f0_; |
| const bfunc_t f1_; |
| }; |
| |
| template <typename T, typename T0_, typename T1_, typename T2_, typename T3_, typename ProcessMode> |
| class T0oT1oT2oT3 : public T0oT1oT2oT3_base_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::bfunc_t bfunc_t; |
| typedef T value_type; |
| typedef T0_ T0; |
| typedef T1_ T1; |
| typedef T2_ T2; |
| typedef T3_ T3; |
| typedef T0oT1oT2oT3<T,T0,T1,T2,T3,ProcessMode> node_type; |
| typedef ProcessMode process_mode_t; |
| |
| T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2), |
| t3_(p3), |
| f0_(p4), |
| f1_(p5), |
| f2_(p6) |
| {} |
| |
| inline T value() const |
| { |
| return ProcessMode::process(t0_,t1_,t2_,t3_,f0_,f1_,f2_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline T2 t2() const |
| { |
| return t2_; |
| } |
| |
| inline T3 t3() const |
| { |
| return t3_; |
| } |
| |
| inline bfunc_t f0() const |
| { |
| return f0_; |
| } |
| |
| inline bfunc_t f1() const |
| { |
| return f1_; |
| } |
| |
| inline bfunc_t f2() const |
| { |
| return f2_; |
| } |
| |
| inline std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return process_mode_t::template id<T0,T1,T2,T3>(); |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, |
| T0 p0, T1 p1, T2 p2, T3 p3, |
| bfunc_t p4, bfunc_t p5, bfunc_t p6) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2,T3,bfunc_t,bfunc_t>(p0,p1,p2,p3,p4,p5,p6); |
| } |
| |
| private: |
| |
| T0oT1oT2oT3(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| T3 t3_; |
| const bfunc_t f0_; |
| const bfunc_t f1_; |
| const bfunc_t f2_; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2> |
| class T0oT1oT2_sf3 : public T0oT1oT2_base_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::tfunc_t tfunc_t; |
| typedef T value_type; |
| typedef T0oT1oT2_sf3<T,T0,T1,T2> node_type; |
| |
| T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2), |
| f_ (p3) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return f_(t0_,t1_,t2_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline T2 t2() const |
| { |
| return t2_; |
| } |
| |
| tfunc_t f() const |
| { |
| return f_; |
| } |
| |
| std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return "sf3"; |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2,tfunc_t>(p0,p1,p2,p3); |
| } |
| |
| private: |
| |
| T0oT1oT2_sf3(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| const tfunc_t f_; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2> |
| class sf3ext_type_node : public T0oT1oT2_base_node<T> |
| { |
| public: |
| |
| virtual ~sf3ext_type_node() |
| {} |
| |
| virtual T0 t0() const = 0; |
| |
| virtual T1 t1() const = 0; |
| |
| virtual T2 t2() const = 0; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2, typename SF3Operation> |
| class T0oT1oT2_sf3ext : public sf3ext_type_node<T,T0,T1,T2> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::tfunc_t tfunc_t; |
| typedef T value_type; |
| typedef T0oT1oT2_sf3ext<T,T0,T1,T2,SF3Operation> node_type; |
| |
| T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return SF3Operation::process(t0_,t1_,t2_); |
| } |
| |
| T0 t0() const |
| { |
| return t0_; |
| } |
| |
| T1 t1() const |
| { |
| return t1_; |
| } |
| |
| T2 t2() const |
| { |
| return t2_; |
| } |
| |
| std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return SF3Operation::id(); |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2>(p0,p1,p2); |
| } |
| |
| private: |
| |
| T0oT1oT2_sf3ext(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| }; |
| |
| template <typename T> |
| inline bool is_sf3ext_node(const expression_node<T>* n) |
| { |
| switch (n->type()) |
| { |
| case expression_node<T>::e_vovov : return true; |
| case expression_node<T>::e_vovoc : return true; |
| case expression_node<T>::e_vocov : return true; |
| case expression_node<T>::e_covov : return true; |
| case expression_node<T>::e_covoc : return true; |
| default : return false; |
| } |
| } |
| |
| template <typename T, typename T0, typename T1, typename T2, typename T3> |
| class T0oT1oT2oT3_sf4 : public T0oT1oT2_base_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::qfunc_t qfunc_t; |
| typedef T value_type; |
| typedef T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> node_type; |
| |
| T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2), |
| t3_(p3), |
| f_ (p4) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return f_(t0_,t1_,t2_,t3_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline T2 t2() const |
| { |
| return t2_; |
| } |
| |
| inline T3 t3() const |
| { |
| return t3_; |
| } |
| |
| qfunc_t f() const |
| { |
| return f_; |
| } |
| |
| std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return "sf4"; |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2,T3,qfunc_t>(p0,p1,p2,p3,p4); |
| } |
| |
| private: |
| |
| T0oT1oT2oT3_sf4(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| T3 t3_; |
| const qfunc_t f_; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2, typename T3, typename SF4Operation> |
| class T0oT1oT2oT3_sf4ext : public T0oT1oT2oT3_base_node<T> |
| { |
| public: |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::tfunc_t tfunc_t; |
| typedef T value_type; |
| typedef T0oT1oT2oT3_sf4ext<T,T0,T1,T2,T3,SF4Operation> node_type; |
| |
| T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) |
| : t0_(p0), |
| t1_(p1), |
| t2_(p2), |
| t3_(p3) |
| {} |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result; |
| return result; |
| } |
| |
| inline operator_type operation() const |
| { |
| return e_default; |
| } |
| |
| inline T value() const |
| { |
| return SF4Operation::process(t0_,t1_,t2_,t3_); |
| } |
| |
| inline T0 t0() const |
| { |
| return t0_; |
| } |
| |
| inline T1 t1() const |
| { |
| return t1_; |
| } |
| |
| inline T2 t2() const |
| { |
| return t2_; |
| } |
| |
| inline T3 t3() const |
| { |
| return t2_; |
| } |
| |
| std::string type_id() const |
| { |
| return id(); |
| } |
| |
| static inline std::string id() |
| { |
| return SF4Operation::id(); |
| } |
| |
| template <typename Allocator> |
| static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) |
| { |
| return allocator.template allocate_type<node_type,T0,T1,T2,T3>(p0,p1,p2,p3); |
| } |
| |
| private: |
| |
| T0oT1oT2oT3_sf4ext(node_type&) {} |
| node_type& operator=(node_type&) { return *this; } |
| |
| T0 t0_; |
| T1 t1_; |
| T2 t2_; |
| T3 t3_; |
| }; |
| |
| template <typename T> |
| inline bool is_sf4ext_node(const expression_node<T>* n) |
| { |
| switch (n->type()) |
| { |
| case expression_node<T>::e_vovovov : return true; |
| case expression_node<T>::e_vovovoc : return true; |
| case expression_node<T>::e_vovocov : return true; |
| case expression_node<T>::e_vocovov : return true; |
| case expression_node<T>::e_covovov : return true; |
| case expression_node<T>::e_covocov : return true; |
| case expression_node<T>::e_vocovoc : return true; |
| case expression_node<T>::e_covovoc : return true; |
| case expression_node<T>::e_vococov : return true; |
| default : return false; |
| } |
| } |
| |
| template <typename T, typename T0, typename T1> |
| struct T0oT1_define |
| { |
| typedef details::T0oT1<T,T0,T1> type0; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2> |
| struct T0oT1oT2_define |
| { |
| typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode0> type0; |
| typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode1> type1; |
| typedef details::T0oT1oT2_sf3<T,T0,T1,T2> sf3_type; |
| typedef details::sf3ext_type_node<T,T0,T1,T2> sf3_type_node; |
| }; |
| |
| template <typename T, typename T0, typename T1, typename T2, typename T3> |
| struct T0oT1oT2oT3_define |
| { |
| typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode0> type0; |
| typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode1> type1; |
| typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode2> type2; |
| typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode3> type3; |
| typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode4> type4; |
| typedef details::T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> sf4_type; |
| }; |
| |
| template <typename T, typename Operation> |
| class vov_node : public vov_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // variable op variable node |
| explicit vov_node(const T& var0, const T& var1) |
| : v0_(var0), |
| v1_(var1) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(v0_,v1_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T& v0() const |
| { |
| return v0_; |
| } |
| |
| inline const T& v1() const |
| { |
| return v1_; |
| } |
| |
| protected: |
| |
| const T& v0_; |
| const T& v1_; |
| |
| private: |
| |
| vov_node(vov_node<T,Operation>&); |
| vov_node<T,Operation>& operator=(vov_node<T,Operation>&); |
| }; |
| |
| template <typename T, typename Operation> |
| class cov_node : public cov_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // constant op variable node |
| explicit cov_node(const T& const_var, const T& var) |
| : c_(const_var), |
| v_(var) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(c_,v_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T c() const |
| { |
| return c_; |
| } |
| |
| inline const T& v() const |
| { |
| return v_; |
| } |
| |
| protected: |
| |
| const T c_; |
| const T& v_; |
| |
| private: |
| |
| cov_node(const cov_node<T,Operation>&); |
| cov_node<T,Operation>& operator=(const cov_node<T,Operation>&); |
| }; |
| |
| template <typename T, typename Operation> |
| class voc_node : public voc_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // variable op constant node |
| explicit voc_node(const T& var, const T& const_var) |
| : v_(var), |
| c_(const_var) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(v_,c_); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T c() const |
| { |
| return c_; |
| } |
| |
| inline const T& v() const |
| { |
| return v_; |
| } |
| |
| protected: |
| |
| const T& v_; |
| const T c_; |
| |
| private: |
| |
| voc_node(const voc_node<T,Operation>&); |
| voc_node<T,Operation>& operator=(const voc_node<T,Operation>&); |
| }; |
| |
| template <typename T, typename Operation> |
| class vob_node : public vob_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef Operation operation_t; |
| |
| // variable op constant node |
| explicit vob_node(const T& var, const expression_ptr brnch) |
| : v_(var) |
| { |
| init_branches<1>(branch_,brnch); |
| } |
| |
| ~vob_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return Operation::process(v_,branch_[0].first->value()); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T& v() const |
| { |
| return v_; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_[0].first; |
| } |
| |
| private: |
| |
| vob_node(const vob_node<T,Operation>&); |
| vob_node<T,Operation>& operator=(const vob_node<T,Operation>&); |
| |
| const T& v_; |
| branch_t branch_[1]; |
| }; |
| |
| template <typename T, typename Operation> |
| class bov_node : public bov_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef Operation operation_t; |
| |
| // variable op constant node |
| explicit bov_node(const expression_ptr brnch, const T& var) |
| : v_(var) |
| { |
| init_branches<1>(branch_,brnch); |
| } |
| |
| ~bov_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return Operation::process(branch_[0].first->value(),v_); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T& v() const |
| { |
| return v_; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_[0].first; |
| } |
| |
| private: |
| |
| bov_node(const bov_node<T,Operation>&); |
| bov_node<T,Operation>& operator=(const bov_node<T,Operation>&); |
| |
| const T& v_; |
| branch_t branch_[1]; |
| }; |
| |
| template <typename T, typename Operation> |
| class cob_node : public cob_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef Operation operation_t; |
| |
| // variable op constant node |
| explicit cob_node(const T const_var, const expression_ptr brnch) |
| : c_(const_var) |
| { |
| init_branches<1>(branch_,brnch); |
| } |
| |
| ~cob_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return Operation::process(c_,branch_[0].first->value()); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T c() const |
| { |
| return c_; |
| } |
| |
| inline void set_c(const T new_c) |
| { |
| (*const_cast<T*>(&c_)) = new_c; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_[0].first; |
| } |
| |
| inline expression_node<T>* move_branch(const std::size_t&) |
| { |
| branch_[0].second = false; |
| return branch_[0].first; |
| } |
| |
| private: |
| |
| cob_node(const cob_node<T,Operation>&); |
| cob_node<T,Operation>& operator=(const cob_node<T,Operation>&); |
| |
| const T c_; |
| branch_t branch_[1]; |
| }; |
| |
| template <typename T, typename Operation> |
| class boc_node : public boc_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr,bool> branch_t; |
| typedef Operation operation_t; |
| |
| // variable op constant node |
| explicit boc_node(const expression_ptr brnch, const T const_var) |
| : c_(const_var) |
| { |
| init_branches<1>(branch_,brnch); |
| } |
| |
| ~boc_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return Operation::process(branch_[0].first->value(),c_); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline const T c() const |
| { |
| return c_; |
| } |
| |
| inline void set_c(const T new_c) |
| { |
| (*const_cast<T*>(&c_)) = new_c; |
| } |
| |
| inline expression_node<T>* branch(const std::size_t&) const |
| { |
| return branch_[0].first; |
| } |
| |
| inline expression_node<T>* move_branch(const std::size_t&) |
| { |
| branch_[0].second = false; |
| return branch_[0].first; |
| } |
| |
| private: |
| |
| boc_node(const boc_node<T,Operation>&); |
| boc_node<T,Operation>& operator=(const boc_node<T,Operation>&); |
| |
| const T c_; |
| branch_t branch_[1]; |
| }; |
| |
| #ifndef exprtk_disable_string_capabilities |
| template <typename T, typename SType0, typename SType1, typename Operation> |
| class sos_node : public sos_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // string op string node |
| explicit sos_node(SType0 p0, SType1 p1) |
| : s0_(p0), |
| s1_(p1) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(s0_,s1_); |
| } |
| |
| inline typename expression_node<T>::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_; |
| |
| private: |
| |
| sos_node(sos_node<T,SType0,SType1,Operation>&); |
| sos_node<T,SType0,SType1,Operation>& operator=(sos_node<T,SType0,SType1,Operation>&); |
| }; |
| |
| template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> |
| class str_xrox_node : public sos_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // string-range op string node |
| explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) |
| : s0_(p0), |
| s1_(p1), |
| rp0_(rp0) |
| {} |
| |
| ~str_xrox_node() |
| { |
| rp0_.free(); |
| } |
| |
| inline T value() const |
| { |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| if (rp0_(r0,r1,s0_.size())) |
| return Operation::process(s0_.substr(r0,(r1 - r0) + 1),s1_); |
| else |
| return T(0); |
| } |
| |
| inline typename expression_node<T>::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_; |
| RangePack rp0_; |
| |
| private: |
| |
| str_xrox_node(str_xrox_node<T,SType0,SType1,RangePack,Operation>&); |
| str_xrox_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xrox_node<T,SType0,SType1,RangePack,Operation>&); |
| }; |
| |
| template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> |
| class str_xoxr_node : public sos_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // string op string range node |
| explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) |
| : s0_ (p0 ), |
| s1_ (p1 ), |
| rp1_(rp1) |
| {} |
| |
| ~str_xoxr_node() |
| { |
| rp1_.free(); |
| } |
| |
| inline T value() const |
| { |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| if (rp1_(r0,r1,s1_.size())) |
| return Operation::process(s0_,s1_.substr(r0,(r1 - r0) + 1)); |
| else |
| return T(0); |
| } |
| |
| inline typename expression_node<T>::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_; |
| RangePack rp1_; |
| |
| private: |
| |
| str_xoxr_node(str_xoxr_node<T,SType0,SType1,RangePack,Operation>&); |
| str_xoxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xoxr_node<T,SType0,SType1,RangePack,Operation>&); |
| }; |
| |
| template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> |
| class str_xroxr_node : public sos_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // string-range op string-range node |
| explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) |
| : s0_ (p0 ), |
| s1_ (p1 ), |
| rp0_(rp0), |
| rp1_(rp1) |
| {} |
| |
| ~str_xroxr_node() |
| { |
| rp0_.free(); |
| rp1_.free(); |
| } |
| |
| inline T value() const |
| { |
| std::size_t r0_0 = 0; |
| std::size_t r0_1 = 0; |
| std::size_t r1_0 = 0; |
| std::size_t r1_1 = 0; |
| if ( |
| rp0_(r0_0,r1_0,s0_.size()) && |
| rp1_(r0_1,r1_1,s1_.size()) |
| ) |
| { |
| return Operation::process( |
| s0_.substr(r0_0,(r1_0 - r0_0) + 1), |
| s1_.substr(r0_1,(r1_1 - r0_1) + 1) |
| ); |
| } |
| else |
| return T(0); |
| } |
| |
| inline typename expression_node<T>::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_; |
| RangePack rp0_; |
| RangePack rp1_; |
| |
| private: |
| |
| str_xroxr_node(str_xroxr_node<T,SType0,SType1,RangePack,Operation>&); |
| str_xroxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xroxr_node<T,SType0,SType1,RangePack,Operation>&); |
| }; |
| |
| template <typename T, typename Operation> |
| class str_sogens_node : public binary_node<T> |
| { |
| public: |
| |
| typedef expression_node <T>* expression_ptr; |
| typedef string_base_node<T>* str_base_ptr; |
| typedef range_pack <T> range_t; |
| typedef range_t* range_ptr; |
| typedef range_interface<T> irange_t; |
| typedef irange_t* irange_ptr; |
| |
| str_sogens_node(const operator_type& opr, |
| expression_ptr branch0, |
| expression_ptr branch1) |
| : binary_node<T>(opr,branch0,branch1), |
| str0_base_ptr_ (0), |
| str1_base_ptr_ (0), |
| str0_range_ptr_(0), |
| str1_range_ptr_(0) |
| { |
| if (is_generally_string_node(binary_node<T>::branch_[0].first)) |
| { |
| str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == str0_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str0_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| |
| if (is_generally_string_node(binary_node<T>::branch_[1].first)) |
| { |
| str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == str1_base_ptr_) |
| return; |
| |
| irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); |
| |
| if (0 == range_ptr) |
| return; |
| |
| str1_range_ptr_ = &(range_ptr->range_ref()); |
| } |
| } |
| |
| inline T value() const |
| { |
| if ( |
| str0_base_ptr_ && |
| str1_base_ptr_ && |
| str0_range_ptr_ && |
| str1_range_ptr_ |
| ) |
| { |
| binary_node<T>::branch_[0].first->value(); |
| binary_node<T>::branch_[1].first->value(); |
| |
| std::size_t str0_r0 = 0; |
| std::size_t str0_r1 = 0; |
| |
| std::size_t str1_r0 = 0; |
| std::size_t str1_r1 = 0; |
| |
| range_t& range0 = (*str0_range_ptr_); |
| range_t& range1 = (*str1_range_ptr_); |
| |
| if ( |
| range0(str0_r0,str0_r1,str0_base_ptr_->size()) && |
| range1(str1_r0,str1_r1,str1_base_ptr_->size()) |
| ) |
| { |
| return Operation::process( |
| str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), |
| str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) |
| ); |
| } |
| } |
| |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| private: |
| |
| str_sogens_node(str_sogens_node<T,Operation>&); |
| str_sogens_node<T,Operation>& operator=(str_sogens_node<T,Operation>&); |
| |
| str_base_ptr str0_base_ptr_; |
| str_base_ptr str1_base_ptr_; |
| range_ptr str0_range_ptr_; |
| range_ptr str1_range_ptr_; |
| }; |
| |
| template <typename T, typename SType0, typename SType1, typename SType2, typename Operation> |
| class sosos_node : public sosos_base_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef Operation operation_t; |
| |
| // variable op variable node |
| explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) |
| : s0_(p0), |
| s1_(p1), |
| s2_(p2) |
| {} |
| |
| inline T value() const |
| { |
| return Operation::process(s0_,s1_,s2_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return Operation::type(); |
| } |
| |
| inline operator_type operation() const |
| { |
| return Operation::operation(); |
| } |
| |
| inline std::string& s0() |
| { |
| return s0_; |
| } |
| |
| inline std::string& s1() |
| { |
| return s1_; |
| } |
| |
| inline std::string& s2() |
| { |
| return s2_; |
| } |
| |
| protected: |
| |
| SType0 s0_; |
| SType1 s1_; |
| SType2 s2_; |
| |
| private: |
| |
| sosos_node(sosos_node<T,SType0,SType1,SType2,Operation>&); |
| sosos_node<T,SType0,SType1,SType2,Operation>& operator=(sosos_node<T,SType0,SType1,SType2,Operation>&); |
| }; |
| #endif |
| |
| template <typename T, typename PowOp> |
| class ipow_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef PowOp operation_t; |
| |
| explicit ipow_node(const T& v) |
| : v_(v) |
| {} |
| |
| inline T value() const |
| { |
| return PowOp::result(v_); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_ipow; |
| } |
| |
| private: |
| |
| ipow_node(const ipow_node<T,PowOp>&); |
| ipow_node<T,PowOp>& operator=(const ipow_node<T,PowOp>&); |
| |
| const T& v_; |
| }; |
| |
| template <typename T, typename PowOp> |
| class bipow_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr, bool> branch_t; |
| typedef PowOp operation_t; |
| |
| explicit bipow_node(expression_ptr brnch) |
| { |
| init_branches<1>(branch_, brnch); |
| } |
| |
| ~bipow_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return PowOp::result(branch_[0].first->value()); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_ipow; |
| } |
| |
| private: |
| |
| bipow_node(const bipow_node<T,PowOp>&); |
| bipow_node<T,PowOp>& operator=(const bipow_node<T,PowOp>&); |
| |
| branch_t branch_[1]; |
| }; |
| |
| template <typename T, typename PowOp> |
| class ipowinv_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef PowOp operation_t; |
| |
| explicit ipowinv_node(const T& v) |
| : v_(v) |
| {} |
| |
| inline T value() const |
| { |
| return (T(1) / PowOp::result(v_)); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_ipowinv; |
| } |
| |
| private: |
| |
| ipowinv_node(const ipowinv_node<T,PowOp>&); |
| ipowinv_node<T,PowOp>& operator=(const ipowinv_node<T,PowOp>&); |
| |
| const T& v_; |
| }; |
| |
| template <typename T, typename PowOp> |
| class bipowninv_node : public expression_node<T> |
| { |
| public: |
| |
| typedef expression_node<T>* expression_ptr; |
| typedef std::pair<expression_ptr, bool> branch_t; |
| typedef PowOp operation_t; |
| |
| explicit bipowninv_node(expression_ptr brnch) |
| { |
| init_branches<1>(branch_, brnch); |
| } |
| |
| ~bipowninv_node() |
| { |
| cleanup_branches::execute<T,1>(branch_); |
| } |
| |
| inline T value() const |
| { |
| return (T(1) / PowOp::result(branch_[0].first->value())); |
| } |
| |
| inline typename expression_node<T>::node_type type() const |
| { |
| return expression_node<T>::e_ipowinv; |
| } |
| |
| private: |
| |
| bipowninv_node(const bipowninv_node<T,PowOp>&); |
| bipowninv_node<T,PowOp>& operator=(const bipowninv_node<T,PowOp>&); |
| |
| branch_t branch_[1]; |
| }; |
| |
| template <typename T> |
| inline bool is_vov_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const vov_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_cov_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const cov_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_voc_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const voc_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_cob_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const cob_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_boc_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const boc_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_t0ot1ot2_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const T0oT1oT2_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_t0ot1ot2ot3_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const T0oT1oT2oT3_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_uv_node(const expression_node<T>* node) |
| { |
| return (0 != dynamic_cast<const uv_base_node<T>*>(node)); |
| } |
| |
| template <typename T> |
| inline bool is_string_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_stringvar == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_range_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_stringvarrng == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_const_string_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_stringconst == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_const_string_range_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_cstringvarrng == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_assignment_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strass == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_concat_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strconcat == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_function_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strfunction == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_condition_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strcondition == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_string_ccondition_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strccondition == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_genricstring_range_node(const expression_node<T>* node) |
| { |
| return node && (expression_node<T>::e_strgenrange == node->type()); |
| } |
| |
| template <typename T> |
| inline bool is_generally_string_node(const expression_node<T>* node) |
| { |
| if (node) |
| { |
| switch (node->type()) |
| { |
| case expression_node<T>::e_stringvar : |
| case expression_node<T>::e_stringconst : |
| case expression_node<T>::e_stringvarrng : |
| case expression_node<T>::e_cstringvarrng : |
| case expression_node<T>::e_strgenrange : |
| case expression_node<T>::e_strass : |
| case expression_node<T>::e_strconcat : |
| case expression_node<T>::e_strfunction : |
| case expression_node<T>::e_strcondition : |
| case expression_node<T>::e_strccondition : return true; |
| default : return false; |
| } |
| } |
| |
| return false; |
| } |
| |
| class node_allocator |
| { |
| public: |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[1]) |
| { |
| return allocate<ResultNode>(operation,branch[0]); |
| } |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[2]) |
| { |
| return allocate<ResultNode>(operation,branch[0],branch[1]); |
| } |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[3]) |
| { |
| return allocate<ResultNode>(operation,branch[0],branch[1],branch[2]); |
| } |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[4]) |
| { |
| return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3]); |
| } |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[5]) |
| { |
| return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4]); |
| } |
| |
| template <typename ResultNode, typename OpType, typename ExprNode> |
| inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[6]) |
| { |
| return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]); |
| } |
| |
| template <typename node_type> |
| inline expression_node<typename node_type::value_type>* allocate() const |
| { |
| return new node_type(); |
| } |
| |
| template <typename node_type, |
| typename Type, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node<typename node_type::value_type>* allocate(const Sequence<Type,Allocator>& seq) const |
| { |
| return new node_type(seq); |
| } |
| |
| template <typename node_type, typename T1> |
| inline expression_node<typename node_type::value_type>* allocate(T1& t1) const |
| { |
| return new node_type(t1); |
| } |
| |
| template <typename node_type, typename T1> |
| inline expression_node<typename node_type::value_type>* allocate_c(const T1& t1) const |
| { |
| return new node_type(t1); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2) const |
| { |
| return new node_type(t1,t2); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2> |
| inline expression_node<typename node_type::value_type>* allocate_cr(const T1& t1, T2& t2) const |
| { |
| return new node_type(t1,t2); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2> |
| inline expression_node<typename node_type::value_type>* allocate_rc(T1& t1, const T2& t2) const |
| { |
| return new node_type(t1,t2); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2> |
| inline expression_node<typename node_type::value_type>* allocate_rr(T1& t1, T2& t2) const |
| { |
| return new node_type(t1,t2); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2> |
| inline expression_node<typename node_type::value_type>* allocate_tt(T1 t1, T2 t2) const |
| { |
| return new node_type(t1,t2); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3> |
| inline expression_node<typename node_type::value_type>* allocate_ttt(T1 t1, T2 t2, T3 t3) const |
| { |
| return new node_type(t1,t2,t3); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3, typename T4> |
| inline expression_node<typename node_type::value_type>* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const |
| { |
| return new node_type(t1,t2,t3,t4); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3> |
| inline expression_node<typename node_type::value_type>* allocate_rrr(T1& t1, T2& t2, T3& t3) const |
| { |
| return new node_type(t1,t2,t3); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3, typename T4> |
| inline expression_node<typename node_type::value_type>* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const |
| { |
| return new node_type(t1,t2,t3,t4); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3, typename T4, typename T5> |
| inline expression_node<typename node_type::value_type>* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const |
| { |
| return new node_type(t1,t2,t3,t4,t5); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3) const |
| { |
| return new node_type(t1,t2,t3); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4) const |
| { |
| return new node_type(t1,t2,t3,t4); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, typename T5> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5) const |
| { |
| return new node_type(t1,t2,t3,t4,t5); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, typename T5, typename T6> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5, const T6& t6) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5, typename T6, typename T7> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5, const T6& t6, |
| const T7& t7) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6,t7); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5, typename T6, |
| typename T7, typename T8> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5, const T6& t6, |
| const T7& t7, const T8& t8) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6,t7,t8); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5, typename T6, |
| typename T7, typename T8, typename T9> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5, const T6& t6, |
| const T7& t7, const T8& t8, |
| const T9& t9) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5, typename T6, |
| typename T7, typename T8, |
| typename T9, typename T10> |
| inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, |
| const T3& t3, const T4& t4, |
| const T5& t5, const T6& t6, |
| const T7& t7, const T8& t8, |
| const T9& t9, const T10& t10) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, typename T3> |
| inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, T3 t3) const |
| { |
| return new node_type(t1,t2,t3); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4> |
| inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, |
| T3 t3, T4 t4) const |
| { |
| return new node_type(t1,t2,t3,t4); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5> |
| inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, |
| T3 t3, T4 t4, |
| T5 t5) const |
| { |
| return new node_type(t1,t2,t3,t4,t5); |
| } |
| |
| template <typename node_type, |
| typename T1, typename T2, |
| typename T3, typename T4, |
| typename T5, typename T6, typename T7> |
| inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, |
| T3 t3, T4 t4, |
| T5 t5, T6 t6, |
| T7 t7) const |
| { |
| return new node_type(t1,t2,t3,t4,t5,t6,t7); |
| } |
| |
| template <typename T> |
| void inline free(expression_node<T>*& e) const |
| { |
| delete e; |
| e = 0; |
| } |
| }; |
| |
| inline void load_operations_map(std::multimap<std::string,details::base_operation_t,details::ilesscompare>& m) |
| { |
| #define register_op(Symbol,Type,Args) \ |
| m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ |
| |
| register_op( "abs",e_abs , 1) |
| register_op( "acos",e_acos , 1) |
| register_op( "acosh",e_acosh , 1) |
| register_op( "asin",e_asin , 1) |
| register_op( "asinh",e_asinh , 1) |
| register_op( "atan",e_atan , 1) |
| register_op( "atanh",e_atanh , 1) |
| register_op( "ceil",e_ceil , 1) |
| register_op( "cos",e_cos , 1) |
| register_op( "cosh",e_cosh , 1) |
| register_op( "exp",e_exp , 1) |
| register_op( "expm1",e_expm1 , 1) |
| register_op( "floor",e_floor , 1) |
| register_op( "log",e_log , 1) |
| register_op( "log10",e_log10 , 1) |
| register_op( "log2",e_log2 , 1) |
| register_op( "log1p",e_log1p , 1) |
| register_op( "round",e_round , 1) |
| register_op( "sin",e_sin , 1) |
| register_op( "sinc",e_sinc , 1) |
| register_op( "sinh",e_sinh , 1) |
| register_op( "sec",e_sec , 1) |
| register_op( "csc",e_csc , 1) |
| register_op( "sqrt",e_sqrt , 1) |
| register_op( "tan",e_tan , 1) |
| register_op( "tanh",e_tanh , 1) |
| register_op( "cot",e_cot , 1) |
| register_op( "rad2deg",e_r2d , 1) |
| register_op( "deg2rad",e_d2r , 1) |
| register_op( "deg2grad",e_d2g , 1) |
| register_op( "grad2deg",e_g2d , 1) |
| register_op( "sgn",e_sgn , 1) |
| register_op( "not",e_notl , 1) |
| register_op( "erf",e_erf , 1) |
| register_op( "erfc",e_erfc , 1) |
| register_op( "ncdf",e_ncdf , 1) |
| register_op( "frac",e_frac , 1) |
| register_op( "trunc",e_trunc , 1) |
| register_op( "atan2",e_atan2 , 2) |
| register_op( "mod",e_mod , 2) |
| register_op( "logn",e_logn , 2) |
| register_op( "pow",e_pow , 2) |
| register_op( "root",e_root , 2) |
| register_op( "roundn",e_roundn , 2) |
| register_op( "equal",e_equal , 2) |
| register_op("not_equal",e_nequal , 2) |
| register_op( "hypot",e_hypot , 2) |
| register_op( "shr",e_shr , 2) |
| register_op( "shl",e_shl , 2) |
| register_op( "clamp",e_clamp , 3) |
| register_op( "iclamp",e_iclamp , 3) |
| register_op( "inrange",e_inrange , 3) |
| #undef register_op |
| } |
| |
| } // namespace details |
| |
| class function_traits |
| { |
| public: |
| |
| function_traits() |
| : allow_zero_parameters_(false), |
| has_side_effects_(true), |
| min_num_args_(0), |
| max_num_args_(std::numeric_limits<std::size_t>::max()) |
| {} |
| |
| inline bool& allow_zero_parameters() |
| { |
| return allow_zero_parameters_; |
| } |
| |
| inline bool& has_side_effects() |
| { |
| return has_side_effects_; |
| } |
| |
| std::size_t& min_num_args() |
| { |
| return min_num_args_; |
| } |
| |
| std::size_t& max_num_args() |
| { |
| return max_num_args_; |
| } |
| |
| private: |
| |
| bool allow_zero_parameters_; |
| bool has_side_effects_; |
| std::size_t min_num_args_; |
| std::size_t max_num_args_; |
| }; |
| |
| template <typename FunctionType> |
| void enable_zero_parameters(FunctionType& func) |
| { |
| func.allow_zero_parameters() = true; |
| |
| if (0 != func.min_num_args()) |
| { |
| func.min_num_args() = 0; |
| } |
| } |
| |
| template <typename FunctionType> |
| void disable_zero_parameters(FunctionType& func) |
| { |
| func.allow_zero_parameters() = false; |
| } |
| |
| template <typename FunctionType> |
| void enable_has_side_effects(FunctionType& func) |
| { |
| func.has_side_effects() = true; |
| } |
| |
| template <typename FunctionType> |
| void disable_has_side_effects(FunctionType& func) |
| { |
| func.has_side_effects() = false; |
| } |
| |
| template <typename FunctionType> |
| void set_min_num_args(FunctionType& func, const std::size_t& num_args) |
| { |
| func.min_num_args() = num_args; |
| |
| if ((0 != func.min_num_args()) && func.allow_zero_parameters()) |
| func.allow_zero_parameters() = false; |
| } |
| |
| template <typename FunctionType> |
| void set_max_num_args(FunctionType& func, const std::size_t& num_args) |
| { |
| func.max_num_args() = num_args; |
| } |
| |
| template <typename T> |
| class ifunction : public function_traits |
| { |
| public: |
| |
| explicit ifunction(const std::size_t& pc) |
| : param_count(pc) |
| {} |
| |
| virtual ~ifunction() |
| {} |
| |
| #define empty_method_body \ |
| { \ |
| return std::numeric_limits<T>::quiet_NaN(); \ |
| } \ |
| |
| inline virtual T operator()() |
| empty_method_body |
| |
| inline virtual T operator()(const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&,const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, |
| const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) |
| empty_method_body |
| |
| #undef empty_method_body |
| |
| std::size_t param_count; |
| }; |
| |
| template <typename T> |
| class ivararg_function : public function_traits |
| { |
| public: |
| |
| virtual ~ivararg_function() |
| {} |
| |
| inline virtual T operator()(const std::vector<T>&) |
| { |
| exprtk_debug(("ivararg_function::operator() - Operator has not been overridden.\n")); |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| }; |
| |
| template <typename T> |
| class igeneric_function : public function_traits |
| { |
| public: |
| |
| enum return_type |
| { |
| e_rtrn_scalar = 0, |
| e_rtrn_string = 1 |
| }; |
| |
| typedef T type; |
| typedef type_store<T> generic_type; |
| typedef typename generic_type::parameter_list parameter_list_t; |
| |
| igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) |
| : parameter_sequence(param_seq), |
| rtrn_type(rtr_type) |
| {} |
| |
| virtual ~igeneric_function() |
| {} |
| |
| #define igeneric_function_empty_body(N) \ |
| { \ |
| exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. ["#N"]\n")); \ |
| return std::numeric_limits<T>::quiet_NaN(); \ |
| } \ |
| |
| // f(i_0,i_1,....,i_N) --> Scalar |
| inline virtual T operator()(parameter_list_t) |
| igeneric_function_empty_body(1) |
| |
| // f(i_0,i_1,....,i_N) --> String |
| inline virtual T operator()(std::string&, parameter_list_t) |
| igeneric_function_empty_body(2) |
| |
| // f(psi,i_0,i_1,....,i_N) --> Scalar |
| inline virtual T operator()(const std::size_t&, parameter_list_t) |
| igeneric_function_empty_body(3) |
| |
| // f(psi,i_0,i_1,....,i_N) --> String |
| inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) |
| igeneric_function_empty_body(4) |
| |
| std::string parameter_sequence; |
| return_type rtrn_type; |
| }; |
| |
| template <typename T> class parser; |
| template <typename T> class expression_helper; |
| |
| template <typename T> |
| class symbol_table |
| { |
| public: |
| |
| typedef T (*ff1_functor)(T); |
| typedef T (*ff2_functor)(T,T); |
| typedef T (*ff3_functor)(T,T,T); |
| typedef T (*ff4_functor)(T,T,T,T); |
| typedef T (*ff5_functor)(T,T,T,T,T); |
| typedef T (*ff6_functor)(T,T,T,T,T,T); |
| |
| protected: |
| |
| struct freefunc1 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc1(ff1_functor ff) : exprtk::ifunction<T>(1), f(ff) {} |
| inline T operator()(const T& v0) |
| { return f(v0); } |
| ff1_functor f; |
| }; |
| |
| struct freefunc2 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc2(ff2_functor ff) : exprtk::ifunction<T>(2), f(ff) {} |
| inline T operator()(const T& v0, const T& v1) |
| { return f(v0,v1); } |
| ff2_functor f; |
| }; |
| |
| struct freefunc3 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc3(ff3_functor ff) : exprtk::ifunction<T>(3), f(ff) {} |
| inline T operator()(const T& v0, const T& v1, const T& v2) |
| { return f(v0,v1,v2); } |
| ff3_functor f; |
| }; |
| |
| struct freefunc4 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc4(ff4_functor ff) : exprtk::ifunction<T>(4), f(ff) {} |
| inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3) |
| { return f(v0,v1,v2,v3); } |
| ff4_functor f; |
| }; |
| |
| struct freefunc5 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc5(ff5_functor ff) : exprtk::ifunction<T>(5), f(ff) {} |
| inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) |
| { return f(v0,v1,v2,v3,v4); } |
| ff5_functor f; |
| }; |
| |
| struct freefunc6 : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| freefunc6(ff6_functor ff) : exprtk::ifunction<T>(6), f(ff) {} |
| inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) |
| { return f(v0,v1,v2,v3,v4,v5); } |
| ff6_functor f; |
| }; |
| |
| template <typename Type, typename RawType> |
| struct type_store |
| { |
| typedef details::expression_node<T>* expression_ptr; |
| typedef typename details::variable_node<T> variable_node_t; |
| typedef ifunction<T> ifunction_t; |
| typedef ivararg_function<T> ivararg_function_t; |
| typedef igeneric_function<T> igeneric_function_t; |
| typedef details::vector_holder<T> vector_t; |
| #ifndef exprtk_disable_string_capabilities |
| typedef typename details::stringvar_node<T> stringvar_node_t; |
| #endif |
| |
| typedef Type type_t; |
| typedef type_t* type_ptr; |
| typedef std::pair<bool,type_ptr> type_pair_t; |
| typedef std::map<std::string,type_pair_t,details::ilesscompare> type_map_t; |
| typedef typename type_map_t::iterator tm_itr_t; |
| typedef typename type_map_t::const_iterator tm_const_itr_t; |
| |
| enum { lut_size = 256 }; |
| |
| type_map_t map; |
| std::size_t size; |
| |
| type_store() |
| : size(0) |
| {} |
| |
| inline bool symbol_exists(const std::string& symbol_name) const |
| { |
| if (symbol_name.empty()) |
| return false; |
| else if (map.end() != map.find(symbol_name)) |
| return true; |
| else |
| return false; |
| } |
| |
| template <typename PtrType> |
| inline std::string entity_name(const PtrType& ptr) const |
| { |
| if (map.empty()) |
| return std::string(); |
| |
| tm_const_itr_t itr = map.begin(); |
| |
| while (map.end() != itr) |
| { |
| if (itr->second.second == ptr) |
| { |
| return itr->first; |
| } |
| else |
| ++itr; |
| } |
| |
| return std::string(); |
| } |
| |
| inline bool is_constant(const std::string& symbol_name) const |
| { |
| if (symbol_name.empty()) |
| return false; |
| else |
| { |
| tm_const_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() == itr) |
| return false; |
| else |
| return (*itr).second.first; |
| } |
| } |
| |
| template <typename Tie, typename RType> |
| inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) |
| { |
| if (symbol_name.size() > 1) |
| { |
| for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) |
| { |
| if (details::imatch(symbol_name,details::reserved_symbols[i])) |
| { |
| return false; |
| } |
| } |
| } |
| |
| tm_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() == itr) |
| { |
| map[symbol_name] = Tie::make(t,is_const); |
| ++size; |
| } |
| |
| return true; |
| } |
| |
| struct tie_array |
| { |
| static inline std::pair<bool,vector_t*> make(std::pair<T*,std::size_t> v, const bool is_const = false) |
| { |
| return std::make_pair(is_const,new vector_t(v.first,v.second)); |
| } |
| }; |
| |
| struct tie_stdvec |
| { |
| template <typename Allocator> |
| static inline std::pair<bool,vector_t*> make(std::vector<T,Allocator>& v, const bool is_const = false) |
| { |
| return std::make_pair(is_const,new vector_t(v)); |
| } |
| }; |
| |
| struct tie_vecview |
| { |
| static inline std::pair<bool,vector_t*> make(exprtk::vector_view<T>& v, const bool is_const = false) |
| { |
| return std::make_pair(is_const,new vector_t(v)); |
| } |
| }; |
| |
| struct tie_stddeq |
| { |
| template <typename Allocator> |
| static inline std::pair<bool,vector_t*> make(std::deque<T,Allocator>& v, const bool is_const = false) |
| { |
| return std::make_pair(is_const,new vector_t(v)); |
| } |
| }; |
| |
| template <std::size_t v_size> |
| inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) |
| { |
| return add_impl<tie_array,std::pair<T*,std::size_t> >(symbol_name,std::make_pair(v,v_size),is_const); |
| } |
| |
| inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) |
| { |
| return add_impl<tie_array,std::pair<T*,std::size_t> >(symbol_name,std::make_pair(v,v_size),is_const); |
| } |
| |
| template <typename Allocator> |
| inline bool add(const std::string& symbol_name, std::vector<T,Allocator>& v, const bool is_const = false) |
| { |
| return add_impl<tie_stdvec,std::vector<T,Allocator>&>(symbol_name,v,is_const); |
| } |
| |
| inline bool add(const std::string& symbol_name, exprtk::vector_view<T>& v, const bool is_const = false) |
| { |
| return add_impl<tie_vecview,exprtk::vector_view<T>&>(symbol_name,v,is_const); |
| } |
| |
| template <typename Allocator> |
| inline bool add(const std::string& symbol_name, std::deque<T,Allocator>& v, const bool is_const = false) |
| { |
| return add_impl<tie_stddeq,std::deque<T,Allocator>&>(symbol_name,v,is_const); |
| } |
| |
| inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) |
| { |
| struct tie |
| { |
| static inline std::pair<bool,variable_node_t*> make(T& t,const bool is_const = false) |
| { |
| return std::make_pair(is_const,new variable_node_t(t)); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| static inline std::pair<bool,stringvar_node_t*> make(std::string& t,const bool is_const = false) |
| { |
| return std::make_pair(is_const,new stringvar_node_t(t)); |
| } |
| #endif |
| |
| static inline std::pair<bool,function_t*> make(function_t& t, const bool is_constant = false) |
| { |
| return std::make_pair(is_constant,&t); |
| } |
| |
| static inline std::pair<bool,vararg_function_t*> make(vararg_function_t& t, const bool is_const = false) |
| { |
| return std::make_pair(is_const,&t); |
| } |
| |
| static inline std::pair<bool,generic_function_t*> make(generic_function_t& t, const bool is_constant = false) |
| { |
| return std::make_pair(is_constant,&t); |
| } |
| }; |
| |
| tm_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() == itr) |
| { |
| map[symbol_name] = tie::make(t,is_const); |
| ++size; |
| } |
| |
| return true; |
| } |
| |
| inline type_ptr get(const std::string& symbol_name) const |
| { |
| tm_const_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() == itr) |
| return reinterpret_cast<type_ptr>(0); |
| else |
| return itr->second.second; |
| } |
| |
| template <typename TType, typename TRawType, typename PtrType> |
| struct ptr_match |
| { |
| static inline bool test(const PtrType, const void*) |
| { |
| return false; |
| } |
| }; |
| |
| template <typename TType, typename TRawType> |
| struct ptr_match<TType,TRawType,variable_node_t*> |
| { |
| static inline bool test(const variable_node_t* p, const void* ptr) |
| { |
| exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); |
| return (&(p->ref()) == ptr); |
| } |
| }; |
| |
| inline type_ptr get_from_varptr(const void* ptr) const |
| { |
| tm_const_itr_t itr = map.begin(); |
| |
| while (map.end() != itr) |
| { |
| type_ptr ret_ptr = itr->second.second; |
| |
| if (ptr_match<Type,RawType,type_ptr>::test(ret_ptr,ptr)) |
| { |
| return ret_ptr; |
| } |
| |
| ++itr; |
| } |
| |
| return type_ptr(0); |
| } |
| |
| inline bool remove(const std::string& symbol_name, const bool delete_node = true) |
| { |
| tm_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() != itr) |
| { |
| struct deleter |
| { |
| static inline void process(std::pair<bool,variable_node_t*>& n) { delete n.second; } |
| static inline void process(std::pair<bool,vector_t*>& n) { delete n.second; } |
| #ifndef exprtk_disable_string_capabilities |
| static inline void process(std::pair<bool,stringvar_node_t*>& n) { delete n.second; } |
| #endif |
| static inline void process(std::pair<bool,function_t*>&) { } |
| }; |
| |
| if (delete_node) |
| { |
| deleter::process((*itr).second); |
| } |
| |
| map.erase(itr); |
| --size; |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| inline RawType& type_ref(const std::string& symbol_name) |
| { |
| struct init_type |
| { |
| static inline double set(double) { return (0.0); } |
| static inline double set(long double) { return (0.0); } |
| static inline float set(float) { return (0.0f); } |
| static inline std::string set(std::string) { return std::string(""); } |
| }; |
| |
| static RawType null_type = init_type::set(RawType()); |
| |
| tm_const_itr_t itr = map.find(symbol_name); |
| |
| if (map.end() == itr) |
| return null_type; |
| else |
| return itr->second.second->ref(); |
| } |
| |
| inline void clear(const bool delete_node = true) |
| { |
| struct deleter |
| { |
| static inline void process(std::pair<bool,variable_node_t*>& n) { delete n.second; } |
| static inline void process(std::pair<bool,vector_t*>& n) { delete n.second; } |
| static inline void process(std::pair<bool,function_t*>&) { } |
| #ifndef exprtk_disable_string_capabilities |
| static inline void process(std::pair<bool,stringvar_node_t*>& n) { delete n.second; } |
| #endif |
| }; |
| |
| if (!map.empty()) |
| { |
| if (delete_node) |
| { |
| tm_itr_t itr = map.begin(); |
| tm_itr_t end = map.end(); |
| |
| while (end != itr) |
| { |
| deleter::process((*itr).second); |
| ++itr; |
| } |
| } |
| |
| map.clear(); |
| } |
| |
| size = 0; |
| } |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_list(Sequence<std::pair<std::string,RawType>,Allocator>& list) const |
| { |
| std::size_t count = 0; |
| |
| if (!map.empty()) |
| { |
| tm_const_itr_t itr = map.begin(); |
| tm_const_itr_t end = map.end(); |
| |
| while (end != itr) |
| { |
| list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); |
| ++itr; |
| ++count; |
| } |
| } |
| |
| return count; |
| } |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_list(Sequence<std::string,Allocator>& vlist) const |
| { |
| std::size_t count = 0; |
| |
| if (!map.empty()) |
| { |
| tm_const_itr_t itr = map.begin(); |
| tm_const_itr_t end = map.end(); |
| |
| while (end != itr) |
| { |
| vlist.push_back((*itr).first); |
| ++itr; |
| ++count; |
| } |
| } |
| |
| return count; |
| } |
| }; |
| |
| typedef details::expression_node<T>* expression_ptr; |
| typedef typename details::variable_node<T> variable_t; |
| typedef typename details::vector_holder<T> vector_holder_t; |
| typedef variable_t* variable_ptr; |
| #ifndef exprtk_disable_string_capabilities |
| typedef typename details::stringvar_node<T> stringvar_t; |
| typedef stringvar_t* stringvar_ptr; |
| #endif |
| typedef ifunction <T> function_t; |
| typedef ivararg_function <T> vararg_function_t; |
| typedef igeneric_function<T> generic_function_t; |
| typedef function_t* function_ptr; |
| typedef vararg_function_t* vararg_function_ptr; |
| typedef generic_function_t* generic_function_ptr; |
| |
| static const std::size_t lut_size = 256; |
| |
| // Symbol Table Holder |
| struct control_block |
| { |
| struct st_data |
| { |
| type_store<typename details::variable_node<T>,T> variable_store; |
| #ifndef exprtk_disable_string_capabilities |
| type_store<typename details::stringvar_node<T>,std::string> stringvar_store; |
| #endif |
| type_store<ifunction<T>,ifunction<T> > function_store; |
| type_store<ivararg_function <T>,ivararg_function <T> > vararg_function_store; |
| type_store<igeneric_function<T>,igeneric_function<T> > generic_function_store; |
| type_store<igeneric_function<T>,igeneric_function<T> > string_function_store; |
| type_store<vector_holder_t,vector_holder_t> vector_store; |
| |
| st_data() |
| { |
| for (std::size_t i = 0; i < details::reserved_words_size; ++i) |
| { |
| reserved_symbol_table_.insert(details::reserved_words[i]); |
| } |
| |
| for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) |
| { |
| reserved_symbol_table_.insert(details::reserved_symbols[i]); |
| } |
| } |
| |
| ~st_data() |
| { |
| for (std::size_t i = 0; i < free_function_list_.size(); ++i) |
| { |
| delete free_function_list_[i]; |
| } |
| } |
| |
| inline bool is_reserved_symbol(const std::string& symbol) const |
| { |
| return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); |
| } |
| |
| std::list<T> local_symbol_list_; |
| std::list<std::string> local_stringvar_list_; |
| std::set<std::string> reserved_symbol_table_; |
| std::vector<ifunction<T>*> free_function_list_; |
| }; |
| |
| control_block() |
| : ref_count(1), |
| data_(new st_data) |
| {} |
| |
| control_block(st_data* data) |
| : ref_count(1), |
| data_(data) |
| {} |
| |
| ~control_block() |
| { |
| if (data_ && (0 == ref_count)) |
| { |
| delete data_; |
| data_ = 0; |
| } |
| } |
| |
| static inline control_block* create() |
| { |
| return new control_block; |
| } |
| |
| template <typename SymTab> |
| static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) |
| { |
| if (cntrl_blck) |
| { |
| if ( |
| (0 != cntrl_blck->ref_count) && |
| (0 == --cntrl_blck->ref_count) |
| ) |
| { |
| if (sym_tab) |
| sym_tab->clear(); |
| |
| delete cntrl_blck; |
| } |
| |
| cntrl_blck = 0; |
| } |
| } |
| |
| std::size_t ref_count; |
| st_data* data_; |
| }; |
| |
| public: |
| |
| symbol_table() |
| : control_block_(control_block::create()) |
| { |
| clear(); |
| } |
| |
| ~symbol_table() |
| { |
| control_block::destroy(control_block_,this); |
| } |
| |
| symbol_table(const symbol_table<T>& st) |
| { |
| control_block_ = st.control_block_; |
| control_block_->ref_count++; |
| } |
| |
| inline symbol_table<T>& operator=(const symbol_table<T>& st) |
| { |
| if (this != &st) |
| { |
| control_block::destroy(control_block_,reinterpret_cast<symbol_table<T>*>(0)); |
| |
| control_block_ = st.control_block_; |
| control_block_->ref_count++; |
| } |
| |
| return *this; |
| } |
| |
| inline bool operator==(const symbol_table<T>& st) |
| { |
| return (this == &st) || (control_block_ == st.control_block_); |
| } |
| |
| inline void clear_variables(const bool delete_node = true) |
| { |
| local_data().variable_store.clear(delete_node); |
| } |
| |
| inline void clear_functions() |
| { |
| local_data().function_store.clear(); |
| } |
| |
| inline void clear_strings() |
| { |
| #ifndef exprtk_disable_string_capabilities |
| local_data().stringvar_store.clear(); |
| #endif |
| } |
| |
| inline void clear_vectors() |
| { |
| local_data().vector_store.clear(); |
| } |
| |
| inline void clear() |
| { |
| if (!valid()) return; |
| clear_variables(); |
| clear_functions(); |
| clear_strings (); |
| clear_vectors (); |
| } |
| |
| inline std::size_t variable_count() const |
| { |
| if (valid()) |
| return local_data().variable_store.size; |
| else |
| return 0; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline std::size_t stringvar_count() const |
| { |
| if (valid()) |
| return local_data().stringvar_store.size; |
| else |
| return 0; |
| } |
| #endif |
| |
| inline std::size_t function_count() const |
| { |
| if (valid()) |
| return local_data().function_store.size; |
| else |
| return 0; |
| } |
| |
| inline std::size_t vector_count() const |
| { |
| if (valid()) |
| return local_data().vector_store.size; |
| else |
| return 0; |
| } |
| |
| inline variable_ptr get_variable(const std::string& variable_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<variable_ptr>(0); |
| else if (!valid_symbol(variable_name)) |
| return reinterpret_cast<variable_ptr>(0); |
| else |
| return local_data().variable_store.get(variable_name); |
| } |
| |
| inline variable_ptr get_variable(const T& var_ref) const |
| { |
| if (!valid()) |
| return reinterpret_cast<variable_ptr>(0); |
| else |
| return local_data().variable_store.get_from_varptr( |
| reinterpret_cast<const void*>(&var_ref)); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline stringvar_ptr get_stringvar(const std::string& string_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<stringvar_ptr>(0); |
| else if (!valid_symbol(string_name)) |
| return reinterpret_cast<stringvar_ptr>(0); |
| else |
| return local_data().stringvar_store.get(string_name); |
| } |
| #endif |
| |
| inline function_ptr get_function(const std::string& function_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<function_ptr>(0); |
| else if (!valid_symbol(function_name)) |
| return reinterpret_cast<function_ptr>(0); |
| else |
| return local_data().function_store.get(function_name); |
| } |
| |
| inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<vararg_function_ptr>(0); |
| else if (!valid_symbol(vararg_function_name)) |
| return reinterpret_cast<vararg_function_ptr>(0); |
| else |
| return local_data().vararg_function_store.get(vararg_function_name); |
| } |
| |
| inline generic_function_ptr get_generic_function(const std::string& function_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<generic_function_ptr>(0); |
| else if (!valid_symbol(function_name)) |
| return reinterpret_cast<generic_function_ptr>(0); |
| else |
| return local_data().generic_function_store.get(function_name); |
| } |
| |
| inline generic_function_ptr get_string_function(const std::string& function_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<generic_function_ptr>(0); |
| else if (!valid_symbol(function_name)) |
| return reinterpret_cast<generic_function_ptr>(0); |
| else |
| return local_data().string_function_store.get(function_name); |
| } |
| |
| typedef vector_holder_t* vector_holder_ptr; |
| |
| inline vector_holder_ptr get_vector(const std::string& vector_name) const |
| { |
| if (!valid()) |
| return reinterpret_cast<vector_holder_ptr>(0); |
| else if (!valid_symbol(vector_name)) |
| return reinterpret_cast<vector_holder_ptr>(0); |
| else |
| return local_data().vector_store.get(vector_name); |
| } |
| |
| inline T& variable_ref(const std::string& symbol_name) |
| { |
| static T null_var = T(0); |
| if (!valid()) |
| return null_var; |
| else if (!valid_symbol(symbol_name)) |
| return null_var; |
| else |
| return local_data().variable_store.type_ref(symbol_name); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline std::string& stringvar_ref(const std::string& symbol_name) |
| { |
| static std::string null_stringvar; |
| if (!valid()) |
| return null_stringvar; |
| else if (!valid_symbol(symbol_name)) |
| return null_stringvar; |
| else |
| return local_data().stringvar_store.type_ref(symbol_name); |
| } |
| #endif |
| |
| inline bool is_constant_node(const std::string& symbol_name) const |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(symbol_name)) |
| return false; |
| else |
| return local_data().variable_store.is_constant(symbol_name); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool is_constant_string(const std::string& symbol_name) const |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(symbol_name)) |
| return false; |
| else if (!local_data().stringvar_store.symbol_exists(symbol_name)) |
| return false; |
| else |
| return local_data().stringvar_store.is_constant(symbol_name); |
| } |
| #endif |
| |
| inline bool create_variable(const std::string& variable_name, const T& value = T(0)) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(variable_name)) |
| return false; |
| else if (symbol_exists(variable_name)) |
| return false; |
| |
| local_data().local_symbol_list_.push_back(value); |
| T& t = local_data().local_symbol_list_.back(); |
| |
| return add_variable(variable_name,t); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(stringvar_name)) |
| return false; |
| else if (symbol_exists(stringvar_name)) |
| return false; |
| |
| local_data().local_stringvar_list_.push_back(value); |
| std::string& s = local_data().local_stringvar_list_.back(); |
| |
| return add_stringvar(stringvar_name,s); |
| } |
| #endif |
| |
| inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(variable_name)) |
| return false; |
| else if (symbol_exists(variable_name)) |
| return false; |
| else |
| return local_data().variable_store.add(variable_name,t,is_constant); |
| } |
| |
| inline bool add_constant(const std::string& constant_name, const T& value) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(constant_name)) |
| return false; |
| else if (symbol_exists(constant_name)) |
| return false; |
| |
| local_data().local_symbol_list_.push_back(value); |
| T& t = local_data().local_symbol_list_.back(); |
| |
| return add_variable(constant_name,t,true); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(stringvar_name)) |
| return false; |
| else if (symbol_exists(stringvar_name)) |
| return false; |
| else |
| return local_data().stringvar_store.add(stringvar_name,s,is_constant); |
| } |
| #endif |
| |
| inline bool add_function(const std::string& function_name, function_t& function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| else |
| return local_data().function_store.add(function_name,function); |
| } |
| |
| inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vararg_function_name)) |
| return false; |
| else if (symbol_exists(vararg_function_name)) |
| return false; |
| else |
| return local_data().vararg_function_store.add(vararg_function_name,vararg_function); |
| } |
| |
| inline bool add_function(const std::string& function_name, generic_function_t& function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")) |
| return false; |
| else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) |
| return local_data().generic_function_store.add(function_name,function); |
| else if (generic_function_t::e_rtrn_string == function.rtrn_type) |
| return local_data().string_function_store.add(function_name, function); |
| else |
| return false; |
| } |
| |
| inline bool add_function(const std::string& function_name, ff1_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc1(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_function(const std::string& function_name, ff2_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc2(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_function(const std::string& function_name, ff3_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc3(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_function(const std::string& function_name, ff4_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc4(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_function(const std::string& function_name, ff5_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc5(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_function(const std::string& function_name, ff6_functor function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name)) |
| return false; |
| else if (symbol_exists(function_name)) |
| return false; |
| |
| exprtk::ifunction<T>* ifunc = new freefunc6(function); |
| |
| local_data().free_function_list_.push_back(ifunc); |
| |
| return add_function(function_name,(*local_data().free_function_list_.back())); |
| } |
| |
| inline bool add_reserved_function(const std::string& function_name, function_t& function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name,false)) |
| return false; |
| else if (symbol_exists(function_name,false)) |
| return false; |
| else |
| return local_data().function_store.add(function_name,function); |
| } |
| |
| inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vararg_function_name,false)) |
| return false; |
| else if (symbol_exists(vararg_function_name,false)) |
| return false; |
| else |
| return local_data().vararg_function_store.add(vararg_function_name,vararg_function); |
| } |
| |
| inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(function_name,false)) |
| return false; |
| else if (symbol_exists(function_name,false)) |
| return false; |
| else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) |
| return false; |
| else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) |
| return local_data().generic_function_store.add(function_name,function); |
| else if (generic_function_t::e_rtrn_string == function.rtrn_type) |
| return local_data().string_function_store.add(function_name, function); |
| else |
| return false; |
| } |
| |
| template <std::size_t N> |
| inline bool add_vector(const std::string& vector_name, T (&v)[N]) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vector_name)) |
| return false; |
| else if (symbol_exists(vector_name)) |
| return false; |
| else |
| return local_data().vector_store.add(vector_name,v); |
| } |
| |
| inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vector_name)) |
| return false; |
| else if (symbol_exists(vector_name)) |
| return false; |
| else |
| return local_data().vector_store.add(vector_name,v,v_size); |
| } |
| |
| template <typename Allocator> |
| inline bool add_vector(const std::string& vector_name, std::vector<T,Allocator>& v) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vector_name)) |
| return false; |
| else if (symbol_exists(vector_name)) |
| return false; |
| else |
| return local_data().vector_store.add(vector_name,v); |
| } |
| |
| inline bool add_vector(const std::string& vector_name, exprtk::vector_view<T>& v) |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(vector_name)) |
| return false; |
| else if (symbol_exists(vector_name)) |
| return false; |
| else |
| return local_data().vector_store.add(vector_name,v); |
| } |
| |
| inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().variable_store.remove(variable_name, delete_node); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool remove_stringvar(const std::string& string_name) |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().stringvar_store.remove(string_name); |
| } |
| #endif |
| |
| inline bool remove_function(const std::string& function_name) |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().function_store.remove(function_name); |
| } |
| |
| inline bool remove_vararg_function(const std::string& vararg_function_name) |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().vararg_function_store.remove(vararg_function_name); |
| } |
| |
| inline bool remove_vector(const std::string& vector_name) |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().vector_store.remove(vector_name); |
| } |
| |
| inline bool add_constants() |
| { |
| return add_pi () && |
| add_epsilon () && |
| add_infinity(); |
| } |
| |
| inline bool add_pi() |
| { |
| static const T local_pi = T(details::numeric::constant::pi); |
| return add_constant("pi",local_pi); |
| } |
| |
| inline bool add_epsilon() |
| { |
| static const T local_epsilon = details::numeric::details::epsilon_type<T>::value(); |
| return add_constant("epsilon",local_epsilon); |
| } |
| |
| inline bool add_infinity() |
| { |
| static const T local_infinity = std::numeric_limits<T>::infinity(); |
| return add_constant("inf",local_infinity); |
| } |
| |
| template <typename Package> |
| inline bool add_package(Package& package) |
| { |
| return package.register_package(*this); |
| } |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_variable_list(Sequence<std::pair<std::string,T>,Allocator>& vlist) const |
| { |
| if (!valid()) |
| return 0; |
| else |
| return local_data().variable_store.get_list(vlist); |
| } |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_variable_list(Sequence<std::string,Allocator>& vlist) const |
| { |
| if (!valid()) |
| return 0; |
| else |
| return local_data().variable_store.get_list(vlist); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_stringvar_list(Sequence<std::pair<std::string,std::string>,Allocator>& svlist) const |
| { |
| if (!valid()) |
| return 0; |
| else |
| return local_data().stringvar_store.get_list(svlist); |
| } |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_stringvar_list(Sequence<std::string,Allocator>& svlist) const |
| { |
| if (!valid()) |
| return 0; |
| else |
| return local_data().stringvar_store.get_list(svlist); |
| } |
| #endif |
| |
| template <typename Allocator, |
| template <typename, typename> class Sequence> |
| inline std::size_t get_vector_list(Sequence<std::string,Allocator>& vlist) const |
| { |
| if (!valid()) |
| return 0; |
| else |
| return local_data().vector_store.get_list(vlist); |
| } |
| |
| inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const |
| { |
| /* |
| Function will return true if symbol_name exists as either a |
| reserved symbol, variable, stringvar or function name in any |
| of the type stores. |
| */ |
| if (!valid()) |
| return false; |
| else if (local_data().variable_store.symbol_exists(symbol_name)) |
| return true; |
| #ifndef exprtk_disable_string_capabilities |
| else if (local_data().stringvar_store.symbol_exists(symbol_name)) |
| return true; |
| #endif |
| else if (local_data().function_store.symbol_exists(symbol_name)) |
| return true; |
| else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) |
| return true; |
| else |
| return false; |
| } |
| |
| inline bool is_variable(const std::string& variable_name) const |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().variable_store.symbol_exists(variable_name); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool is_stringvar(const std::string& stringvar_name) const |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().stringvar_store.symbol_exists(stringvar_name); |
| } |
| |
| inline bool is_conststr_stringvar(const std::string& symbol_name) const |
| { |
| if (!valid()) |
| return false; |
| else if (!valid_symbol(symbol_name)) |
| return false; |
| else if (!local_data().stringvar_store.symbol_exists(symbol_name)) |
| return false; |
| |
| return ( |
| local_data().stringvar_store.symbol_exists(symbol_name) || |
| local_data().stringvar_store.is_constant (symbol_name) |
| ); |
| } |
| #endif |
| |
| inline bool is_function(const std::string& function_name) const |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().function_store.symbol_exists(function_name); |
| } |
| |
| inline bool is_vararg_function(const std::string& vararg_function_name) const |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().vararg_function_store.symbol_exists(vararg_function_name); |
| } |
| |
| inline bool is_vector(const std::string& vector_name) const |
| { |
| if (!valid()) |
| return false; |
| else |
| return local_data().vector_store.symbol_exists(vector_name); |
| } |
| |
| inline std::string get_variable_name(const expression_ptr& ptr) const |
| { |
| return local_data().variable_store.entity_name(ptr); |
| } |
| |
| inline std::string get_vector_name(const vector_holder_ptr& ptr) const |
| { |
| return local_data().vector_store.entity_name(ptr); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline std::string get_stringvar_name(const expression_ptr& ptr) const |
| { |
| return local_data().stringvar_store.entity_name(ptr); |
| } |
| |
| inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const |
| { |
| return local_data().stringvar_store.entity_name(ptr); |
| } |
| #endif |
| |
| inline bool valid() const |
| { |
| // Symbol table sanity check. |
| return control_block_ && control_block_->data_; |
| } |
| |
| inline void load_from(const symbol_table<T>& st) |
| { |
| { |
| std::vector<std::string> name_list; |
| |
| st.local_data().function_store.get_list(name_list); |
| |
| if (!name_list.empty()) |
| { |
| for (std::size_t i = 0; i < name_list.size(); ++i) |
| { |
| exprtk::ifunction<T>& ifunc = *st.get_function(name_list[i]); |
| add_function(name_list[i],ifunc); |
| } |
| } |
| } |
| |
| { |
| std::vector<std::string> name_list; |
| |
| st.local_data().vararg_function_store.get_list(name_list); |
| |
| if (!name_list.empty()) |
| { |
| for (std::size_t i = 0; i < name_list.size(); ++i) |
| { |
| exprtk::ivararg_function<T>& ivafunc = *st.get_vararg_function(name_list[i]); |
| add_function(name_list[i],ivafunc); |
| } |
| } |
| } |
| |
| { |
| std::vector<std::string> name_list; |
| |
| st.local_data().generic_function_store.get_list(name_list); |
| |
| if (!name_list.empty()) |
| { |
| for (std::size_t i = 0; i < name_list.size(); ++i) |
| { |
| exprtk::igeneric_function<T>& ifunc = *st.get_generic_function(name_list[i]); |
| add_function(name_list[i],ifunc); |
| } |
| } |
| } |
| |
| { |
| std::vector<std::string> name_list; |
| |
| st.local_data().string_function_store.get_list(name_list); |
| |
| if (!name_list.empty()) |
| { |
| for (std::size_t i = 0; i < name_list.size(); ++i) |
| { |
| exprtk::igeneric_function<T>& ifunc = *st.get_string_function(name_list[i]); |
| add_function(name_list[i],ifunc); |
| } |
| } |
| } |
| } |
| |
| private: |
| |
| inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const |
| { |
| if (symbol.empty()) |
| return false; |
| else if (!details::is_letter(symbol[0])) |
| return false; |
| else if (symbol.size() > 1) |
| { |
| for (std::size_t i = 1; i < symbol.size(); ++i) |
| { |
| if ( |
| !details::is_letter_or_digit(symbol[i]) && |
| ('_' != symbol[i]) |
| ) |
| { |
| if (('.' == symbol[i]) && (i < (symbol.size() - 1))) |
| continue; |
| else |
| return false; |
| } |
| } |
| } |
| |
| return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; |
| } |
| |
| inline bool valid_function(const std::string& symbol) const |
| { |
| if (symbol.empty()) |
| return false; |
| else if (!details::is_letter(symbol[0])) |
| return false; |
| else if (symbol.size() > 1) |
| { |
| for (std::size_t i = 1; i < symbol.size(); ++i) |
| { |
| if ( |
| !details::is_letter_or_digit(symbol[i]) && |
| ('_' != symbol[i]) |
| ) |
| { |
| if (('.' == symbol[i]) && (i < (symbol.size() - 1))) |
| continue; |
| else |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| typedef typename control_block::st_data local_data_t; |
| |
| inline local_data_t& local_data() |
| { |
| return *(control_block_->data_); |
| } |
| |
| inline const local_data_t& local_data() const |
| { |
| return *(control_block_->data_); |
| } |
| |
| control_block* control_block_; |
| |
| friend class parser<T>; |
| }; |
| |
| template <typename T> |
| class function_compositor; |
| |
| template <typename T> |
| class expression |
| { |
| private: |
| |
| typedef details::expression_node<T>* expression_ptr; |
| typedef details::vector_holder<T>* vector_holder_ptr; |
| typedef std::vector<symbol_table<T> > symtab_list_t; |
| |
| struct control_block |
| { |
| enum data_type |
| { |
| e_unknown , |
| e_expr , |
| e_vecholder, |
| e_data , |
| e_vecdata , |
| e_string |
| }; |
| |
| struct data_pack |
| { |
| data_pack() |
| : pointer(0), |
| type(e_unknown), |
| size(0) |
| {} |
| |
| data_pack(void* ptr, data_type dt, std::size_t sz = 0) |
| : pointer(ptr), |
| type(dt), |
| size(sz) |
| {} |
| |
| void* pointer; |
| data_type type; |
| std::size_t size; |
| }; |
| |
| typedef std::vector<data_pack> local_data_list_t; |
| typedef results_context<T> results_context_t; |
| |
| control_block() |
| : ref_count(0), |
| expr (0), |
| results (0), |
| retinv_null(false), |
| return_invoked(&retinv_null) |
| {} |
| |
| control_block(expression_ptr e) |
| : ref_count(1), |
| expr (e), |
| results (0), |
| retinv_null(false), |
| return_invoked(&retinv_null) |
| {} |
| |
| ~control_block() |
| { |
| if (expr && details::branch_deletable(expr)) |
| { |
| delete expr; |
| expr = reinterpret_cast<expression_ptr>(0); |
| } |
| |
| if (!local_data_list.empty()) |
| { |
| for (std::size_t i = 0; i < local_data_list.size(); ++i) |
| { |
| switch (local_data_list[i].type) |
| { |
| case e_expr : delete reinterpret_cast<expression_ptr>(local_data_list[i].pointer); |
| break; |
| |
| case e_vecholder : delete reinterpret_cast<vector_holder_ptr>(local_data_list[i].pointer); |
| break; |
| |
| case e_data : delete (T*)(local_data_list[i].pointer); |
| break; |
| |
| case e_vecdata : delete [] (T*)(local_data_list[i].pointer); |
| break; |
| |
| case e_string : delete (std::string*)(local_data_list[i].pointer); |
| break; |
| |
| default : break; |
| } |
| } |
| } |
| |
| if (results) |
| { |
| delete results; |
| } |
| } |
| |
| static inline control_block* create(expression_ptr e) |
| { |
| return new control_block(e); |
| } |
| |
| static inline void destroy(control_block*& cntrl_blck) |
| { |
| if (cntrl_blck) |
| { |
| if ( |
| (0 != cntrl_blck->ref_count) && |
| (0 == --cntrl_blck->ref_count) |
| ) |
| { |
| delete cntrl_blck; |
| } |
| |
| cntrl_blck = 0; |
| } |
| } |
| |
| std::size_t ref_count; |
| expression_ptr expr; |
| local_data_list_t local_data_list; |
| results_context_t* results; |
| bool retinv_null; |
| bool* return_invoked; |
| |
| friend class function_compositor<T>; |
| }; |
| |
| public: |
| |
| expression() |
| : control_block_(0) |
| { |
| set_expression(new details::null_node<T>()); |
| } |
| |
| expression(const expression<T>& e) |
| : control_block_(e.control_block_), |
| symbol_table_list_(e.symbol_table_list_) |
| { |
| control_block_->ref_count++; |
| } |
| |
| inline expression<T>& operator=(const expression<T>& e) |
| { |
| if (this != &e) |
| { |
| if (control_block_) |
| { |
| if ( |
| (0 != control_block_->ref_count) && |
| (0 == --control_block_->ref_count) |
| ) |
| { |
| delete control_block_; |
| } |
| |
| control_block_ = 0; |
| } |
| |
| control_block_ = e.control_block_; |
| control_block_->ref_count++; |
| symbol_table_list_ = e.symbol_table_list_; |
| } |
| |
| return *this; |
| } |
| |
| inline bool operator==(const expression<T>& e) |
| { |
| return (this == &e); |
| } |
| |
| inline bool operator!() const |
| { |
| return ( |
| (0 == control_block_ ) || |
| (0 == control_block_->expr) |
| ); |
| } |
| |
| inline expression<T>& release() |
| { |
| control_block::destroy(control_block_); |
| |
| return *this; |
| } |
| |
| ~expression() |
| { |
| control_block::destroy(control_block_); |
| } |
| |
| inline T value() const |
| { |
| return control_block_->expr->value(); |
| } |
| |
| inline T operator()() const |
| { |
| return value(); |
| } |
| |
| inline operator T() const |
| { |
| return value(); |
| } |
| |
| inline operator bool() const |
| { |
| return details::is_true(value()); |
| } |
| |
| inline void register_symbol_table(symbol_table<T>& st) |
| { |
| symbol_table_list_.push_back(st); |
| } |
| |
| inline const symbol_table<T>& get_symbol_table(const std::size_t& index = 0) const |
| { |
| return symbol_table_list_[index]; |
| } |
| |
| inline symbol_table<T>& get_symbol_table(const std::size_t& index = 0) |
| { |
| return symbol_table_list_[index]; |
| } |
| |
| typedef results_context<T> results_context_t; |
| |
| inline const results_context_t& results() const |
| { |
| if (control_block_->results) |
| return (*control_block_->results); |
| else |
| { |
| static const results_context_t null_results; |
| return null_results; |
| } |
| } |
| |
| inline bool return_invoked() const |
| { |
| return (*control_block_->return_invoked); |
| } |
| |
| private: |
| |
| inline symtab_list_t get_symbol_table_list() const |
| { |
| return symbol_table_list_; |
| } |
| |
| inline void set_expression(const expression_ptr expr) |
| { |
| if (expr) |
| { |
| if (control_block_) |
| { |
| if (0 == --control_block_->ref_count) |
| { |
| delete control_block_; |
| } |
| } |
| |
| control_block_ = control_block::create(expr); |
| } |
| } |
| |
| inline void register_local_var(expression_ptr expr) |
| { |
| if (expr) |
| { |
| if (control_block_) |
| { |
| control_block_-> |
| local_data_list.push_back( |
| typename expression<T>::control_block:: |
| data_pack(reinterpret_cast<void*>(expr), |
| control_block::e_expr)); |
| } |
| } |
| } |
| |
| inline void register_local_var(vector_holder_ptr vec_holder) |
| { |
| if (vec_holder) |
| { |
| if (control_block_) |
| { |
| control_block_-> |
| local_data_list.push_back( |
| typename expression<T>::control_block:: |
| data_pack(reinterpret_cast<void*>(vec_holder), |
| control_block::e_vecholder)); |
| } |
| } |
| } |
| |
| inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) |
| { |
| if (data) |
| { |
| if (control_block_) |
| { |
| typename control_block::data_type dt = control_block::e_data; |
| |
| switch (data_mode) |
| { |
| case 0 : dt = control_block::e_data; break; |
| case 1 : dt = control_block::e_vecdata; break; |
| case 2 : dt = control_block::e_string; break; |
| } |
| |
| control_block_-> |
| local_data_list.push_back( |
| typename expression<T>::control_block:: |
| data_pack(reinterpret_cast<void*>(data),dt,size)); |
| } |
| } |
| } |
| |
| inline const typename control_block::local_data_list_t& local_data_list() |
| { |
| if (control_block_) |
| { |
| return control_block_->local_data_list; |
| } |
| else |
| { |
| static typename control_block::local_data_list_t null_local_data_list; |
| return null_local_data_list; |
| } |
| } |
| |
| inline void register_return_results(results_context_t* rc) |
| { |
| if (control_block_ && rc) |
| { |
| control_block_->results = rc; |
| } |
| } |
| |
| inline void set_retinvk(bool* retinvk_ptr) |
| { |
| if (control_block_) |
| { |
| control_block_->return_invoked = retinvk_ptr; |
| } |
| } |
| |
| control_block* control_block_; |
| symtab_list_t symbol_table_list_; |
| |
| friend class parser<T>; |
| friend class expression_helper<T>; |
| friend class function_compositor<T>; |
| }; |
| |
| template <typename T> |
| class expression_helper |
| { |
| public: |
| |
| static inline bool is_constant(const expression<T>& expr) |
| { |
| return details::is_constant_node(expr.control_block_->expr); |
| } |
| |
| static inline bool is_variable(const expression<T>& expr) |
| { |
| return details::is_variable_node(expr.control_block_->expr); |
| } |
| |
| static inline bool is_unary(const expression<T>& expr) |
| { |
| return details::is_unary_node(expr.control_block_->expr); |
| } |
| |
| static inline bool is_binary(const expression<T>& expr) |
| { |
| return details::is_binary_node(expr.control_block_->expr); |
| } |
| |
| static inline bool is_function(const expression<T>& expr) |
| { |
| return details::is_function(expr.control_block_->expr); |
| } |
| |
| static inline bool is_null(const expression<T>& expr) |
| { |
| return details::is_null_node(expr.control_block_->expr); |
| } |
| }; |
| |
| template <typename T> |
| inline bool is_valid(const expression<T>& expr) |
| { |
| return !expression_helper<T>::is_null(expr); |
| } |
| |
| namespace parser_error |
| { |
| enum error_mode |
| { |
| e_unknown = 0, |
| e_syntax = 1, |
| e_token = 2, |
| e_numeric = 4, |
| e_symtab = 5, |
| e_lexer = 6, |
| e_helper = 7 |
| }; |
| |
| struct type |
| { |
| type() |
| : mode(parser_error::e_unknown), |
| line_no (0), |
| column_no(0) |
| {} |
| |
| lexer::token token; |
| error_mode mode; |
| std::string diagnostic; |
| std::string error_line; |
| std::size_t line_no; |
| std::size_t column_no; |
| }; |
| |
| inline type make_error(error_mode mode, const std::string& diagnostic = "") |
| { |
| type t; |
| t.mode = mode; |
| t.token.type = lexer::token::e_error; |
| t.diagnostic = diagnostic; |
| exprtk_debug(("%s\n",diagnostic .c_str())); |
| return t; |
| } |
| |
| inline type make_error(error_mode mode, const lexer::token& tk, const std::string& diagnostic = "") |
| { |
| type t; |
| t.mode = mode; |
| t.token = tk; |
| t.diagnostic = diagnostic; |
| exprtk_debug(("%s\n",diagnostic .c_str())); |
| return t; |
| } |
| |
| inline std::string to_str(error_mode mode) |
| { |
| switch (mode) |
| { |
| case e_unknown : return std::string("Unknown Error"); |
| case e_syntax : return std::string("Syntax Error" ); |
| case e_token : return std::string("Token Error" ); |
| case e_numeric : return std::string("Numeric Error"); |
| case e_symtab : return std::string("Symbol Error" ); |
| case e_lexer : return std::string("Lexer Error" ); |
| case e_helper : return std::string("Helper Error" ); |
| default : return std::string("Unknown Error"); |
| } |
| } |
| |
| inline bool update_error(type& error, const std::string& expression) |
| { |
| if ( |
| expression.empty() || |
| (error.token.position > expression.size()) || |
| (std::numeric_limits<std::size_t>::max() == error.token.position) |
| ) |
| { |
| return false; |
| } |
| |
| std::size_t error_line_start = 0; |
| |
| for (std::size_t i = error.token.position; i > 0; --i) |
| { |
| const details::char_t c = expression[i]; |
| |
| if (('\n' == c) || ('\r' == c)) |
| { |
| error_line_start = i + 1; |
| break; |
| } |
| } |
| |
| std::size_t next_nl_position = std::min(expression.size(), |
| expression.find_first_of('\n',error.token.position + 1)); |
| |
| error.column_no = error.token.position - error_line_start; |
| error.error_line = expression.substr(error_line_start, |
| next_nl_position - error_line_start); |
| |
| error.line_no = 0; |
| |
| for (std::size_t i = 0; i < next_nl_position; ++i) |
| { |
| if ('\n' == expression[i]) |
| ++error.line_no; |
| } |
| |
| return true; |
| } |
| |
| inline void dump_error(const type& error) |
| { |
| printf("Position: %02d Type: [%s] Msg: %s\n", |
| static_cast<int>(error.token.position), |
| exprtk::parser_error::to_str(error.mode).c_str(), |
| error.diagnostic.c_str()); |
| } |
| } |
| |
| template <typename T> |
| class parser : public lexer::parser_helper |
| { |
| private: |
| |
| enum precedence_level |
| { |
| e_level00, |
| e_level01, |
| e_level02, |
| e_level03, |
| e_level04, |
| e_level05, |
| e_level06, |
| e_level07, |
| e_level08, |
| e_level09, |
| e_level10, |
| e_level11, |
| e_level12, |
| e_level13, |
| e_level14 |
| }; |
| |
| typedef const T& cref_t; |
| typedef const T const_t; |
| typedef ifunction <T> F; |
| typedef ivararg_function <T> VAF; |
| typedef igeneric_function <T> GF; |
| typedef ifunction <T> ifunction_t; |
| typedef ivararg_function <T> ivararg_function_t; |
| typedef igeneric_function <T> igeneric_function_t; |
| typedef details::expression_node <T> expression_node_t; |
| typedef details::literal_node <T> literal_node_t; |
| typedef details::unary_node <T> unary_node_t; |
| typedef details::binary_node <T> binary_node_t; |
| typedef details::trinary_node <T> trinary_node_t; |
| typedef details::quaternary_node <T> quaternary_node_t; |
| typedef details::conditional_node<T> conditional_node_t; |
| typedef details::cons_conditional_node<T> cons_conditional_node_t; |
| typedef details::while_loop_node <T> while_loop_node_t; |
| typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t; |
| typedef details::for_loop_node <T> for_loop_node_t; |
| #ifndef exprtk_disable_break_continue |
| typedef details::while_loop_bc_node <T> while_loop_bc_node_t; |
| typedef details::repeat_until_loop_bc_node<T> repeat_until_loop_bc_node_t; |
| typedef details::for_loop_bc_node<T> for_loop_bc_node_t; |
| #endif |
| typedef details::switch_node <T> switch_node_t; |
| typedef details::variable_node <T> variable_node_t; |
| typedef details::vector_elem_node<T> vector_elem_node_t; |
| typedef details::rebasevector_elem_node<T> rebasevector_elem_node_t; |
| typedef details::rebasevector_celem_node<T> rebasevector_celem_node_t; |
| typedef details::vector_node <T> vector_node_t; |
| typedef details::range_pack <T> range_t; |
| #ifndef exprtk_disable_string_capabilities |
| typedef details::stringvar_node <T> stringvar_node_t; |
| typedef details::string_literal_node<T> string_literal_node_t; |
| typedef details::string_range_node <T> string_range_node_t; |
| typedef details::const_string_range_node<T> const_string_range_node_t; |
| typedef details::generic_string_range_node<T> generic_string_range_node_t; |
| typedef details::string_concat_node <T> string_concat_node_t; |
| typedef details::assignment_string_node<T> assignment_string_node_t; |
| typedef details::assignment_string_range_node<T> assignment_string_range_node_t; |
| typedef details::conditional_string_node<T> conditional_string_node_t; |
| typedef details::cons_conditional_str_node<T> cons_conditional_str_node_t; |
| #endif |
| typedef details::assignment_node<T> assignment_node_t; |
| typedef details::assignment_vec_elem_node <T> assignment_vec_elem_node_t; |
| typedef details::assignment_rebasevec_elem_node <T> assignment_rebasevec_elem_node_t; |
| typedef details::assignment_rebasevec_celem_node<T> assignment_rebasevec_celem_node_t; |
| typedef details::assignment_vec_node <T> assignment_vec_node_t; |
| typedef details::assignment_vecvec_node <T> assignment_vecvec_node_t; |
| typedef details::scand_node<T> scand_node_t; |
| typedef details::scor_node<T> scor_node_t; |
| typedef lexer::token token_t; |
| typedef expression_node_t* expression_node_ptr; |
| typedef symbol_table<T> symbol_table_t; |
| typedef typename expression<T>::symtab_list_t symbol_table_list_t; |
| typedef details::vector_holder<T>* vector_holder_ptr; |
| |
| typedef typename details::functor_t<T> functor_t; |
| typedef typename functor_t::qfunc_t quaternary_functor_t; |
| typedef typename functor_t::tfunc_t trinary_functor_t; |
| typedef typename functor_t::bfunc_t binary_functor_t; |
| typedef typename functor_t::ufunc_t unary_functor_t; |
| |
| typedef details::operator_type operator_t; |
| |
| typedef std::map<operator_t, unary_functor_t> unary_op_map_t; |
| typedef std::map<operator_t, binary_functor_t> binary_op_map_t; |
| typedef std::map<operator_t,trinary_functor_t> trinary_op_map_t; |
| |
| typedef std::map<std::string,std::pair<trinary_functor_t ,operator_t> > sf3_map_t; |
| typedef std::map<std::string,std::pair<quaternary_functor_t,operator_t> > sf4_map_t; |
| |
| typedef std::map<binary_functor_t,operator_t> inv_binary_op_map_t; |
| typedef std::multimap<std::string,details::base_operation_t,details::ilesscompare> base_ops_map_t; |
| typedef std::set<std::string,details::ilesscompare> disabled_func_set_t; |
| |
| typedef details::T0oT1_define<T, cref_t, cref_t> vov_t; |
| typedef details::T0oT1_define<T,const_t, cref_t> cov_t; |
| typedef details::T0oT1_define<T, cref_t,const_t> voc_t; |
| |
| typedef details::T0oT1oT2_define<T, cref_t, cref_t, cref_t> vovov_t; |
| typedef details::T0oT1oT2_define<T, cref_t, cref_t,const_t> vovoc_t; |
| typedef details::T0oT1oT2_define<T, cref_t,const_t, cref_t> vocov_t; |
| typedef details::T0oT1oT2_define<T,const_t, cref_t, cref_t> covov_t; |
| typedef details::T0oT1oT2_define<T,const_t, cref_t,const_t> covoc_t; |
| typedef details::T0oT1oT2_define<T,const_t,const_t, cref_t> cocov_t; |
| typedef details::T0oT1oT2_define<T,cref_t,const_t, const_t> vococ_t; |
| |
| typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, cref_t> vovovov_t; |
| typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t,const_t> vovovoc_t; |
| typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t,const_t, cref_t> vovocov_t; |
| typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t, cref_t> vocovov_t; |
| typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t, cref_t> covovov_t; |
| |
| typedef details::T0oT1oT2oT3_define<T,const_t, cref_t,const_t, cref_t> covocov_t; |
| typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t,const_t> vocovoc_t; |
| typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t,const_t> covovoc_t; |
| typedef details::T0oT1oT2oT3_define<T, cref_t,const_t,const_t, cref_t> vococov_t; |
| |
| typedef results_context<T> results_context_t; |
| |
| typedef parser_helper prsrhlpr_t; |
| |
| struct scope_element |
| { |
| enum element_type |
| { |
| e_none , |
| e_variable, |
| e_vector , |
| e_vecelem , |
| e_string |
| }; |
| |
| typedef details::vector_holder<T> vector_holder_t; |
| typedef variable_node_t* variable_node_ptr; |
| typedef vector_holder_t* vector_holder_ptr; |
| typedef expression_node_t* expression_node_ptr; |
| #ifndef exprtk_disable_string_capabilities |
| typedef stringvar_node_t* stringvar_node_ptr; |
| #endif |
| |
| scope_element() |
| : name("???"), |
| size (std::numeric_limits<std::size_t>::max()), |
| index(std::numeric_limits<std::size_t>::max()), |
| depth(std::numeric_limits<std::size_t>::max()), |
| ref_count(0), |
| ip_index (0), |
| type (e_none), |
| active(false), |
| data (0), |
| var_node(0), |
| vec_node(0) |
| #ifndef exprtk_disable_string_capabilities |
| ,str_node(0) |
| #endif |
| {} |
| |
| bool operator < (const scope_element& se) const |
| { |
| if (ip_index < se.ip_index) |
| return true; |
| else if (ip_index > se.ip_index) |
| return false; |
| else if (depth < se.depth) |
| return true; |
| else if (depth > se.depth) |
| return false; |
| else if (index < se.index) |
| return true; |
| else if (index > se.index) |
| return false; |
| else |
| return (name < se.name); |
| } |
| |
| void clear() |
| { |
| name = "???"; |
| size = std::numeric_limits<std::size_t>::max(); |
| index = std::numeric_limits<std::size_t>::max(); |
| depth = std::numeric_limits<std::size_t>::max(); |
| type = e_none; |
| active = false; |
| ref_count = 0; |
| ip_index = 0; |
| data = 0; |
| var_node = 0; |
| vec_node = 0; |
| #ifndef exprtk_disable_string_capabilities |
| str_node = 0; |
| #endif |
| } |
| |
| std::string name; |
| std::size_t size; |
| std::size_t index; |
| std::size_t depth; |
| std::size_t ref_count; |
| std::size_t ip_index; |
| element_type type; |
| bool active; |
| void* data; |
| expression_node_ptr var_node; |
| vector_holder_ptr vec_node; |
| #ifndef exprtk_disable_string_capabilities |
| stringvar_node_ptr str_node; |
| #endif |
| }; |
| |
| class scope_element_manager |
| { |
| public: |
| |
| typedef expression_node_t* expression_node_ptr; |
| typedef variable_node_t* variable_node_ptr; |
| typedef parser<T> parser_t; |
| |
| scope_element_manager(parser<T>& p) |
| : parser_(p), |
| input_param_cnt_(0) |
| {} |
| |
| inline std::size_t size() const |
| { |
| return element_.size(); |
| } |
| |
| inline bool empty() const |
| { |
| return element_.empty(); |
| } |
| |
| inline scope_element& get_element(const std::size_t& index) |
| { |
| if (index < element_.size()) |
| return element_[index]; |
| else |
| return null_element_; |
| } |
| |
| inline scope_element& get_element(const std::string& var_name, |
| const std::size_t index = std::numeric_limits<std::size_t>::max()) |
| { |
| const std::size_t current_depth = parser_.state_.scope_depth; |
| |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| scope_element& se = element_[i]; |
| |
| if (se.depth > current_depth) |
| continue; |
| else if ( |
| (se.name == var_name) && |
| (se.index == index) |
| ) |
| return se; |
| } |
| |
| return null_element_; |
| } |
| |
| inline scope_element& get_active_element(const std::string& var_name, |
| const std::size_t index = std::numeric_limits<std::size_t>::max()) |
| { |
| const std::size_t current_depth = parser_.state_.scope_depth; |
| |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| scope_element& se = element_[i]; |
| |
| if (se.depth > current_depth) |
| continue; |
| else if ( |
| (se.name == var_name) && |
| (se.index == index) && |
| (se.active) |
| ) |
| return se; |
| } |
| |
| return null_element_; |
| } |
| |
| inline bool add_element(const scope_element& se) |
| { |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| scope_element& cse = element_[i]; |
| |
| if ( |
| (cse.name == se.name ) && |
| (cse.depth <= se.depth) && |
| (cse.index == se.index) && |
| (cse.size == se.size ) && |
| (cse.type == se.type ) && |
| (cse.active) |
| ) |
| return false; |
| } |
| |
| element_.push_back(se); |
| std::sort(element_.begin(),element_.end()); |
| |
| return true; |
| } |
| |
| inline void deactivate(const std::size_t& scope_depth) |
| { |
| exprtk_debug(("deactivate() - Scope depth: %d\n", |
| static_cast<int>(parser_.state_.scope_depth))); |
| |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| scope_element& se = element_[i]; |
| |
| if (se.active && (se.depth >= scope_depth)) |
| { |
| exprtk_debug(("deactivate() - element[%02d] '%s'\n", |
| static_cast<int>(i), |
| se.name.c_str())); |
| |
| se.active = false; |
| } |
| } |
| } |
| |
| inline void free_element(scope_element& se) |
| { |
| switch (se.type) |
| { |
| case scope_element::e_variable : if (se.data ) delete (T*) se.data; |
| if (se.var_node) delete se.var_node; |
| break; |
| |
| case scope_element::e_vector : if (se.data ) delete[] (T*) se.data; |
| if (se.vec_node) delete se.vec_node; |
| break; |
| |
| case scope_element::e_vecelem : if (se.var_node) delete se.var_node; |
| break; |
| |
| #ifndef exprtk_disable_string_capabilities |
| case scope_element::e_string : if (se.data ) delete (std::string*) se.data; |
| if (se.str_node) delete se.str_node; |
| break; |
| #endif |
| |
| default : return; |
| } |
| |
| se.clear(); |
| } |
| |
| inline void cleanup() |
| { |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| free_element(element_[i]); |
| } |
| |
| element_.clear(); |
| |
| input_param_cnt_ = 0; |
| } |
| |
| inline std::size_t next_ip_index() |
| { |
| return ++input_param_cnt_; |
| } |
| |
| inline expression_node_ptr get_variable(const T& v) |
| { |
| for (std::size_t i = 0; i < element_.size(); ++i) |
| { |
| scope_element& se = element_[i]; |
| |
| if ( |
| se.active && |
| se.var_node && |
| details::is_variable_node(se.var_node) |
| ) |
| { |
| variable_node_ptr vn = reinterpret_cast<variable_node_ptr>(se.var_node); |
| |
| if (&(vn->ref()) == (&v)) |
| { |
| return se.var_node; |
| } |
| } |
| } |
| |
| return expression_node_ptr(0); |
| } |
| |
| private: |
| |
| scope_element_manager& operator=(const scope_element_manager&); |
| |
| parser_t& parser_; |
| std::vector<scope_element> element_; |
| scope_element null_element_; |
| std::size_t input_param_cnt_; |
| }; |
| |
| class scope_handler |
| { |
| public: |
| |
| typedef parser<T> parser_t; |
| |
| scope_handler(parser<T>& p) |
| : parser_(p) |
| { |
| parser_.state_.scope_depth++; |
| #ifdef exprtk_enable_debugging |
| std::string depth(2 * parser_.state_.scope_depth,'-'); |
| exprtk_debug(("%s> Scope Depth: %02d\n", |
| depth.c_str(), |
| static_cast<int>(parser_.state_.scope_depth))); |
| #endif |
| } |
| |
| ~scope_handler() |
| { |
| parser_.sem_.deactivate(parser_.state_.scope_depth); |
| parser_.state_.scope_depth--; |
| #ifdef exprtk_enable_debugging |
| std::string depth(2 * parser_.state_.scope_depth,'-'); |
| exprtk_debug(("<%s Scope Depth: %02d\n", |
| depth.c_str(), |
| static_cast<int>(parser_.state_.scope_depth))); |
| #endif |
| } |
| |
| private: |
| |
| scope_handler& operator=(const scope_handler&); |
| |
| parser_t& parser_; |
| }; |
| |
| struct symtab_store |
| { |
| symbol_table_list_t symtab_list_; |
| |
| typedef typename symbol_table_t::local_data_t local_data_t; |
| typedef typename symbol_table_t::variable_ptr variable_ptr; |
| typedef typename symbol_table_t::function_ptr function_ptr; |
| #ifndef exprtk_disable_string_capabilities |
| typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; |
| #endif |
| typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; |
| typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; |
| typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; |
| |
| inline bool empty() const |
| { |
| return symtab_list_.empty(); |
| } |
| |
| inline void clear() |
| { |
| symtab_list_.clear(); |
| } |
| |
| inline bool valid() const |
| { |
| if (!empty()) |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (symtab_list_[i].valid()) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| inline bool valid_symbol(const std::string& symbol) const |
| { |
| if (!symtab_list_.empty()) |
| return symtab_list_[0].valid_symbol(symbol); |
| else |
| return false; |
| } |
| |
| inline bool valid_function_name(const std::string& symbol) const |
| { |
| if (!symtab_list_.empty()) |
| return symtab_list_[0].valid_function(symbol); |
| else |
| return false; |
| } |
| |
| inline variable_ptr get_variable(const std::string& variable_name) const |
| { |
| if (!valid_symbol(variable_name)) |
| return reinterpret_cast<variable_ptr>(0); |
| |
| variable_ptr result = reinterpret_cast<variable_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i) |
| .variable_store.get(variable_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline variable_ptr get_variable(const T& var_ref) const |
| { |
| variable_ptr result = reinterpret_cast<variable_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i).variable_store |
| .get_from_varptr(reinterpret_cast<const void*>(&var_ref)); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline stringvar_ptr get_stringvar(const std::string& string_name) const |
| { |
| if (!valid_symbol(string_name)) |
| return reinterpret_cast<stringvar_ptr>(0); |
| |
| stringvar_ptr result = reinterpret_cast<stringvar_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i) |
| .stringvar_store.get(string_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| #endif |
| |
| inline function_ptr get_function(const std::string& function_name) const |
| { |
| if (!valid_function_name(function_name)) |
| return reinterpret_cast<function_ptr>(0); |
| |
| function_ptr result = reinterpret_cast<function_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i) |
| .function_store.get(function_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const |
| { |
| if (!valid_function_name(vararg_function_name)) |
| return reinterpret_cast<vararg_function_ptr>(0); |
| |
| vararg_function_ptr result = reinterpret_cast<vararg_function_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i) |
| .vararg_function_store.get(vararg_function_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline generic_function_ptr get_generic_function(const std::string& function_name) const |
| { |
| if (!valid_function_name(function_name)) |
| return reinterpret_cast<generic_function_ptr>(0); |
| |
| generic_function_ptr result = reinterpret_cast<generic_function_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = local_data(i) |
| .generic_function_store.get(function_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline generic_function_ptr get_string_function(const std::string& function_name) const |
| { |
| if (!valid_function_name(function_name)) |
| return reinterpret_cast<generic_function_ptr>(0); |
| |
| generic_function_ptr result = reinterpret_cast<generic_function_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = |
| local_data(i).string_function_store.get(function_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline vector_holder_ptr get_vector(const std::string& vector_name) const |
| { |
| if (!valid_symbol(vector_name)) |
| return reinterpret_cast<vector_holder_ptr>(0); |
| |
| vector_holder_ptr result = reinterpret_cast<vector_holder_ptr>(0); |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else |
| result = |
| local_data(i).vector_store.get(vector_name); |
| |
| if (result) break; |
| } |
| |
| return result; |
| } |
| |
| inline bool is_constant_node(const std::string& symbol_name) const |
| { |
| if (!valid_symbol(symbol_name)) |
| return false; |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if (local_data(i).variable_store.is_constant(symbol_name)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool is_constant_string(const std::string& symbol_name) const |
| { |
| if (!valid_symbol(symbol_name)) |
| return false; |
| |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) |
| continue; |
| else if ( local_data(i).stringvar_store.is_constant(symbol_name)) |
| return true; |
| } |
| |
| return false; |
| } |
| #endif |
| |
| inline bool symbol_exists(const std::string& symbol) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if (symtab_list_[i].symbol_exists(symbol)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline bool is_variable(const std::string& variable_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| symtab_list_[i].local_data().variable_store |
| .symbol_exists(variable_name) |
| ) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool is_stringvar(const std::string& stringvar_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| symtab_list_[i].local_data().stringvar_store |
| .symbol_exists(stringvar_name) |
| ) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline bool is_conststr_stringvar(const std::string& symbol_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| symtab_list_[i].local_data().stringvar_store |
| .symbol_exists(symbol_name) |
| ) |
| { |
| return ( |
| local_data(i).stringvar_store.symbol_exists(symbol_name) || |
| local_data(i).stringvar_store.is_constant (symbol_name) |
| ); |
| |
| } |
| } |
| |
| return false; |
| } |
| #endif |
| |
| inline bool is_function(const std::string& function_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| local_data(i).vararg_function_store |
| .symbol_exists(function_name) |
| ) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline bool is_vararg_function(const std::string& vararg_function_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| local_data(i).vararg_function_store |
| .symbol_exists(vararg_function_name) |
| ) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline bool is_vector(const std::string& vector_name) const |
| { |
| for (std::size_t i = 0; i < symtab_list_.size(); ++i) |
| { |
| if (!symtab_list_[i].valid()) |
| continue; |
| else if ( |
| local_data(i).vector_store |
| .symbol_exists(vector_name) |
| ) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| inline std::string get_variable_name(const expression_node_ptr& ptr) const |
| { |
| return local_data().variable_store.entity_name(ptr); |
| } |
| |
| inline std::string get_vector_name(const vector_holder_ptr& ptr) const |
| { |
| return local_data().vector_store.entity_name(ptr); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline std::string get_stringvar_name(const expression_node_ptr& ptr) const |
| { |
| return local_data().stringvar_store.entity_name(ptr); |
| } |
| |
| inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const |
| { |
| return local_data().stringvar_store.entity_name(ptr); |
| } |
| #endif |
| |
| inline local_data_t& local_data(const std::size_t& index = 0) |
| { |
| return symtab_list_[index].local_data(); |
| } |
| |
| inline const local_data_t& local_data(const std::size_t& index = 0) const |
| { |
| return symtab_list_[index].local_data(); |
| } |
| |
| inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) |
| { |
| return symtab_list_[index]; |
| } |
| }; |
| |
| struct parser_state |
| { |
| parser_state() |
| { |
| reset(); |
| } |
| |
| void reset() |
| { |
| parsing_return_stmt = false; |
| parsing_break_stmt = false; |
| return_stmt_present = false; |
| side_effect_present = false; |
| scope_depth = 0; |
| } |
| |
| #ifndef exprtk_enable_debugging |
| void activate_side_effect(const std::string&) |
| #else |
| void activate_side_effect(const std::string& source) |
| #endif |
| { |
| if (!side_effect_present) |
| { |
| side_effect_present = true; |
| |
| exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); |
| } |
| } |
| |
| bool parsing_return_stmt; |
| bool parsing_break_stmt; |
| bool return_stmt_present; |
| bool side_effect_present; |
| std::size_t scope_depth; |
| }; |
| |
| public: |
| |
| struct unknown_symbol_resolver |
| { |
| |
| enum usr_symbol_type |
| { |
| e_usr_variable_type = 0, |
| e_usr_constant_type = 1 |
| }; |
| |
| virtual ~unknown_symbol_resolver() |
| {} |
| |
| virtual bool process(const std::string& /*unknown_symbol*/, |
| usr_symbol_type& st, |
| T& default_value, |
| std::string& error_message) |
| { |
| st = e_usr_variable_type; |
| default_value = T(0); |
| error_message.clear(); |
| |
| return true; |
| } |
| }; |
| |
| enum collect_type |
| { |
| e_ct_none = 0, |
| e_ct_variables = 1, |
| e_ct_functions = 2, |
| e_ct_assignments = 4 |
| }; |
| |
| enum symbol_type |
| { |
| e_st_unknown = 0, |
| e_st_variable = 1, |
| e_st_vector = 2, |
| e_st_vecelem = 3, |
| e_st_string = 4, |
| e_st_function = 5, |
| e_st_local_variable = 6, |
| e_st_local_vector = 7, |
| e_st_local_string = 8 |
| }; |
| |
| class dependent_entity_collector |
| { |
| public: |
| |
| typedef std::pair<std::string,symbol_type> symbol_t; |
| typedef std::vector<symbol_t> symbol_list_t; |
| |
| dependent_entity_collector(const std::size_t options = e_ct_none) |
| : options_(options), |
| collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), |
| collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), |
| collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), |
| return_present_ (false), |
| final_stmt_return_(false) |
| {} |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline std::size_t symbols(Sequence<symbol_t,Allocator>& symbols_list) |
| { |
| if (!collect_variables_ && !collect_functions_) |
| return 0; |
| else if (symbol_name_list_.empty()) |
| return 0; |
| |
| for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) |
| { |
| std::string& s = symbol_name_list_[i].first; |
| std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower)); |
| } |
| |
| std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); |
| |
| std::unique_copy(symbol_name_list_.begin(), |
| symbol_name_list_.end(), |
| std::back_inserter(symbols_list)); |
| |
| return symbols_list.size(); |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline std::size_t assignment_symbols(Sequence<symbol_t,Allocator>& assignment_list) |
| { |
| if (!collect_assignments_) |
| return 0; |
| else if (assignment_name_list_.empty()) |
| return 0; |
| |
| for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) |
| { |
| std::string& s = assignment_name_list_[i].first; |
| std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower)); |
| } |
| |
| std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); |
| |
| std::unique_copy(assignment_name_list_.begin(), |
| assignment_name_list_.end(), |
| std::back_inserter(assignment_list)); |
| |
| return assignment_list.size(); |
| } |
| |
| void clear() |
| { |
| symbol_name_list_ .clear(); |
| assignment_name_list_.clear(); |
| retparam_list_ .clear(); |
| return_present_ = false; |
| final_stmt_return_ = false; |
| } |
| |
| bool& collect_variables() |
| { |
| return collect_variables_; |
| } |
| |
| bool& collect_functions() |
| { |
| return collect_functions_; |
| } |
| |
| bool& collect_assignments() |
| { |
| return collect_assignments_; |
| } |
| |
| bool return_present() const |
| { |
| return return_present_; |
| } |
| |
| bool final_stmt_return() const |
| { |
| return final_stmt_return_; |
| } |
| |
| typedef std::vector<std::string> retparam_list_t; |
| |
| retparam_list_t return_param_type_list() const |
| { |
| return retparam_list_; |
| } |
| |
| private: |
| |
| inline void add_symbol(const std::string& symbol, const symbol_type st) |
| { |
| switch (st) |
| { |
| case e_st_variable : |
| case e_st_vector : |
| case e_st_string : |
| case e_st_local_variable : |
| case e_st_local_vector : |
| case e_st_local_string : |
| case e_st_function : |
| if (collect_variables_ || collect_functions_) |
| symbol_name_list_.push_back(std::make_pair(symbol,st)); |
| break; |
| |
| default : return; |
| } |
| } |
| |
| inline void add_assignment(const std::string& symbol, const symbol_type st) |
| { |
| switch (st) |
| { |
| case e_st_variable : |
| case e_st_vector : |
| case e_st_string : |
| if (collect_assignments_) |
| assignment_name_list_.push_back(std::make_pair(symbol,st)); |
| break; |
| |
| default : return; |
| } |
| } |
| |
| std::size_t options_; |
| bool collect_variables_; |
| bool collect_functions_; |
| bool collect_assignments_; |
| bool return_present_; |
| bool final_stmt_return_; |
| symbol_list_t symbol_name_list_; |
| symbol_list_t assignment_name_list_; |
| retparam_list_t retparam_list_; |
| |
| friend class parser<T>; |
| }; |
| |
| class settings_store |
| { |
| private: |
| |
| typedef std::set<std::string,details::ilesscompare> disabled_entity_set_t; |
| typedef disabled_entity_set_t::iterator des_itr_t; |
| |
| public: |
| |
| enum settings_compilation_options |
| { |
| e_unknown = 0, |
| e_replacer = 1, |
| e_joiner = 2, |
| e_numeric_check = 4, |
| e_bracket_check = 8, |
| e_sequence_check = 16, |
| e_commutative_check = 32, |
| e_strength_reduction = 64, |
| e_disable_vardef = 128, |
| e_collect_vars = 256, |
| e_collect_funcs = 512, |
| e_collect_assings = 1024, |
| e_disable_usr_on_rsrvd = 2048, |
| e_disable_zero_return = 4096 |
| }; |
| |
| enum settings_base_funcs |
| { |
| e_bf_unknown = 0, |
| e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , |
| e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , |
| e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , |
| e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , |
| e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , |
| e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , |
| e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , |
| e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , |
| e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , |
| e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , |
| e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , |
| e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , |
| e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , |
| e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, |
| e_bf_rad2deg , e_bf_grad2deg |
| }; |
| |
| enum settings_control_structs |
| { |
| e_ctrl_unknown = 0, |
| e_ctrl_ifelse, |
| e_ctrl_switch, |
| e_ctrl_for_loop, |
| e_ctrl_while_loop, |
| e_ctrl_repeat_loop |
| }; |
| |
| enum settings_logic_opr |
| { |
| e_logic_unknown = 0, |
| e_logic_and, e_logic_nand, e_logic_nor, |
| e_logic_not, e_logic_or, e_logic_xnor, |
| e_logic_xor, e_logic_scand, e_logic_scor |
| }; |
| |
| enum settings_arithmetic_opr |
| { |
| e_arith_unknown = 0, |
| e_arith_add, e_arith_sub, e_arith_mul, |
| e_arith_div, e_arith_mod, e_arith_pow |
| }; |
| |
| enum settings_assignment_opr |
| { |
| e_assign_unknown = 0, |
| e_assign_assign, e_assign_addass, e_assign_subass, |
| e_assign_mulass, e_assign_divass, e_assign_modass |
| }; |
| |
| enum settings_inequality_opr |
| { |
| e_ineq_unknown = 0, |
| e_ineq_lt, e_ineq_lte, e_ineq_eq, |
| e_ineq_equal, e_ineq_ne, e_ineq_nequal, |
| e_ineq_gte, e_ineq_gt |
| }; |
| |
| static const std::size_t compile_all_opts = e_replacer + |
| e_joiner + |
| e_numeric_check + |
| e_bracket_check + |
| e_sequence_check + |
| e_commutative_check + |
| e_strength_reduction; |
| |
| settings_store(const std::size_t compile_options = compile_all_opts) |
| { |
| load_compile_options(compile_options); |
| } |
| |
| settings_store& enable_all_base_functions() |
| { |
| disabled_func_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_all_control_structures() |
| { |
| disabled_ctrl_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_all_logic_ops() |
| { |
| disabled_logic_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_all_arithmetic_ops() |
| { |
| disabled_arithmetic_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_all_assignment_ops() |
| { |
| disabled_assignment_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_all_inequality_ops() |
| { |
| disabled_inequality_set_.clear(); |
| return *this; |
| } |
| |
| settings_store& enable_local_vardef() |
| { |
| disable_vardef_ = false; |
| return *this; |
| } |
| |
| settings_store& disable_all_base_functions() |
| { |
| std::copy(details::base_function_list, |
| details::base_function_list + details::base_function_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_func_set_,disabled_func_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_all_control_structures() |
| { |
| std::copy(details::cntrl_struct_list, |
| details::cntrl_struct_list + details::cntrl_struct_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_ctrl_set_,disabled_ctrl_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_all_logic_ops() |
| { |
| std::copy(details::logic_ops_list, |
| details::logic_ops_list + details::logic_ops_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_logic_set_,disabled_logic_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_all_arithmetic_ops() |
| { |
| std::copy(details::arithmetic_ops_list, |
| details::arithmetic_ops_list + details::arithmetic_ops_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_arithmetic_set_,disabled_arithmetic_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_all_assignment_ops() |
| { |
| std::copy(details::assignment_ops_list, |
| details::assignment_ops_list + details::assignment_ops_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_assignment_set_,disabled_assignment_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_all_inequality_ops() |
| { |
| std::copy(details::inequality_ops_list, |
| details::inequality_ops_list + details::inequality_ops_list_size, |
| std::insert_iterator<disabled_entity_set_t> |
| (disabled_inequality_set_,disabled_inequality_set_.begin())); |
| return *this; |
| } |
| |
| settings_store& disable_local_vardef() |
| { |
| disable_vardef_ = true; |
| return *this; |
| } |
| |
| bool replacer_enabled () const { return enable_replacer_; } |
| bool commutative_check_enabled () const { return enable_commutative_check_; } |
| bool joiner_enabled () const { return enable_joiner_; } |
| bool numeric_check_enabled () const { return enable_numeric_check_; } |
| bool bracket_check_enabled () const { return enable_bracket_check_; } |
| bool sequence_check_enabled () const { return enable_sequence_check_; } |
| bool strength_reduction_enabled () const { return enable_strength_reduction_; } |
| bool collect_variables_enabled () const { return enable_collect_vars_; } |
| bool collect_functions_enabled () const { return enable_collect_funcs_; } |
| bool collect_assignments_enabled() const { return enable_collect_assings_; } |
| bool vardef_disabled () const { return disable_vardef_; } |
| bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } |
| bool zero_return_disabled () const { return disable_zero_return_; } |
| |
| bool function_enabled(const std::string& function_name) |
| { |
| if (disabled_func_set_.empty()) |
| return true; |
| else |
| return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); |
| } |
| |
| bool control_struct_enabled(const std::string& control_struct) |
| { |
| if (disabled_ctrl_set_.empty()) |
| return true; |
| else |
| return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); |
| } |
| |
| bool logic_enabled(const std::string& logic_operation) |
| { |
| if (disabled_logic_set_.empty()) |
| return true; |
| else |
| return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); |
| } |
| |
| bool arithmetic_enabled(const details::operator_type& arithmetic_operation) |
| { |
| if (disabled_logic_set_.empty()) |
| return true; |
| else |
| return (disabled_arithmetic_set_.end() == disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); |
| } |
| |
| bool assignment_enabled(const details::operator_type& assignment) |
| { |
| if (disabled_assignment_set_.empty()) |
| return true; |
| else |
| return (disabled_assignment_set_.end() == disabled_assignment_set_.find(assign_opr_to_string(assignment))); |
| } |
| |
| bool inequality_enabled(const details::operator_type& inequality) |
| { |
| if (disabled_inequality_set_.empty()) |
| return true; |
| else |
| return (disabled_inequality_set_.end() == disabled_inequality_set_.find(inequality_opr_to_string(inequality))); |
| } |
| |
| bool function_disabled(const std::string& function_name) |
| { |
| if (disabled_func_set_.empty()) |
| return false; |
| else |
| return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); |
| } |
| |
| bool control_struct_disabled(const std::string& control_struct) |
| { |
| if (disabled_ctrl_set_.empty()) |
| return false; |
| else |
| return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); |
| } |
| |
| bool logic_disabled(const std::string& logic_operation) |
| { |
| if (disabled_logic_set_.empty()) |
| return false; |
| else |
| return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); |
| } |
| |
| bool assignment_disabled(const details::operator_type assignment_operation) |
| { |
| if (disabled_assignment_set_.empty()) |
| return false; |
| else |
| return (disabled_assignment_set_.end() != disabled_assignment_set_.find(assign_opr_to_string(assignment_operation))); |
| } |
| |
| bool arithmetic_disabled(const details::operator_type arithmetic_operation) |
| { |
| if (disabled_arithmetic_set_.empty()) |
| return false; |
| else |
| return (disabled_arithmetic_set_.end() != disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); |
| } |
| |
| bool inequality_disabled(const details::operator_type& inequality) |
| { |
| if (disabled_inequality_set_.empty()) |
| return false; |
| else |
| return (disabled_inequality_set_.end() != disabled_inequality_set_.find(inequality_opr_to_string(inequality))); |
| } |
| |
| settings_store& disable_base_function(settings_base_funcs bf) |
| { |
| if ( |
| (e_bf_unknown != bf) && |
| (static_cast<std::size_t>(bf) < (details::base_function_list_size + 1)) |
| ) |
| { |
| disabled_func_set_.insert(details::base_function_list[bf - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& disable_control_structure(settings_control_structs ctrl_struct) |
| { |
| if ( |
| (e_ctrl_unknown != ctrl_struct) && |
| (static_cast<std::size_t>(ctrl_struct) < (details::cntrl_struct_list_size + 1)) |
| ) |
| { |
| disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& disable_logic_operation(settings_logic_opr logic) |
| { |
| if ( |
| (e_logic_unknown != logic) && |
| (static_cast<std::size_t>(logic) < (details::logic_ops_list_size + 1)) |
| ) |
| { |
| disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) |
| { |
| if ( |
| (e_arith_unknown != arithmetic) && |
| (static_cast<std::size_t>(arithmetic) < (details::arithmetic_ops_list_size + 1)) |
| ) |
| { |
| disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& disable_assignment_operation(settings_assignment_opr assignment) |
| { |
| if ( |
| (e_assign_unknown != assignment) && |
| (static_cast<std::size_t>(assignment) < (details::assignment_ops_list_size + 1)) |
| ) |
| { |
| disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& disable_inequality_operation(settings_inequality_opr inequality) |
| { |
| if ( |
| (e_ineq_unknown != inequality) && |
| (static_cast<std::size_t>(inequality) < (details::inequality_ops_list_size + 1)) |
| ) |
| { |
| disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_base_function(settings_base_funcs bf) |
| { |
| if ( |
| (e_bf_unknown != bf) && |
| (static_cast<std::size_t>(bf) < (details::base_function_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); |
| |
| if (disabled_func_set_.end() != itr) |
| { |
| disabled_func_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_control_structure(settings_control_structs ctrl_struct) |
| { |
| if ( |
| (e_ctrl_unknown != ctrl_struct) && |
| (static_cast<std::size_t>(ctrl_struct) < (details::cntrl_struct_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); |
| |
| if (disabled_ctrl_set_.end() != itr) |
| { |
| disabled_ctrl_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_logic_operation(settings_logic_opr logic) |
| { |
| if ( |
| (e_logic_unknown != logic) && |
| (static_cast<std::size_t>(logic) < (details::logic_ops_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); |
| |
| if (disabled_logic_set_.end() != itr) |
| { |
| disabled_logic_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) |
| { |
| if ( |
| (e_arith_unknown != arithmetic) && |
| (static_cast<std::size_t>(arithmetic) < (details::arithmetic_ops_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); |
| |
| if (disabled_arithmetic_set_.end() != itr) |
| { |
| disabled_arithmetic_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_assignment_operation(settings_assignment_opr assignment) |
| { |
| if ( |
| (e_assign_unknown != assignment) && |
| (static_cast<std::size_t>(assignment) < (details::assignment_ops_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); |
| |
| if (disabled_assignment_set_.end() != itr) |
| { |
| disabled_assignment_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| settings_store& enable_inequality_operation(settings_inequality_opr inequality) |
| { |
| if ( |
| (e_ineq_unknown != inequality) && |
| (static_cast<std::size_t>(inequality) < (details::inequality_ops_list_size + 1)) |
| ) |
| { |
| des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); |
| |
| if (disabled_inequality_set_.end() != itr) |
| { |
| disabled_inequality_set_.erase(itr); |
| } |
| } |
| |
| return *this; |
| } |
| |
| private: |
| |
| void load_compile_options(const std::size_t compile_options) |
| { |
| enable_replacer_ = (compile_options & e_replacer ) == e_replacer; |
| enable_joiner_ = (compile_options & e_joiner ) == e_joiner; |
| enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; |
| enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; |
| enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; |
| enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; |
| enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; |
| enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; |
| enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; |
| enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; |
| disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; |
| disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; |
| disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; |
| } |
| |
| std::string assign_opr_to_string(details::operator_type opr) |
| { |
| switch (opr) |
| { |
| case details::e_assign : return ":="; |
| case details::e_addass : return "+="; |
| case details::e_subass : return "-="; |
| case details::e_mulass : return "*="; |
| case details::e_divass : return "/="; |
| case details::e_modass : return "%="; |
| default : return ""; |
| } |
| } |
| |
| std::string arith_opr_to_string(details::operator_type opr) |
| { |
| switch (opr) |
| { |
| case details::e_add : return "+"; |
| case details::e_sub : return "-"; |
| case details::e_mul : return "*"; |
| case details::e_div : return "/"; |
| case details::e_mod : return "%"; |
| default : return ""; |
| } |
| } |
| |
| std::string inequality_opr_to_string(details::operator_type opr) |
| { |
| switch (opr) |
| { |
| case details::e_lt : return "<"; |
| case details::e_lte : return "<="; |
| case details::e_eq : return "=="; |
| case details::e_equal : return "="; |
| case details::e_ne : return "!="; |
| case details::e_nequal: return "<>"; |
| case details::e_gte : return ">="; |
| case details::e_gt : return ">"; |
| default : return ""; |
| } |
| } |
| |
| bool enable_replacer_; |
| bool enable_joiner_; |
| bool enable_numeric_check_; |
| bool enable_bracket_check_; |
| bool enable_sequence_check_; |
| bool enable_commutative_check_; |
| bool enable_strength_reduction_; |
| bool enable_collect_vars_; |
| bool enable_collect_funcs_; |
| bool enable_collect_assings_; |
| bool disable_vardef_; |
| bool disable_rsrvd_sym_usr_; |
| bool disable_zero_return_; |
| |
| disabled_entity_set_t disabled_func_set_ ; |
| disabled_entity_set_t disabled_ctrl_set_ ; |
| disabled_entity_set_t disabled_logic_set_; |
| disabled_entity_set_t disabled_arithmetic_set_; |
| disabled_entity_set_t disabled_assignment_set_; |
| disabled_entity_set_t disabled_inequality_set_; |
| |
| friend class parser<T>; |
| }; |
| |
| typedef settings_store settings_t; |
| |
| parser(const settings_t& settings = settings_t()) |
| : settings_(settings), |
| resolve_unknown_symbol_(false), |
| results_context_(0), |
| unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)), |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning (disable:4355) |
| #endif |
| sem_(*this), |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| operator_joiner_2_(2), |
| operator_joiner_3_(3) |
| { |
| init_precompilation(); |
| |
| load_operations_map (base_ops_map_ ); |
| load_unary_operations_map (unary_op_map_ ); |
| load_binary_operations_map (binary_op_map_ ); |
| load_inv_binary_operations_map(inv_binary_op_map_); |
| load_sf3_map (sf3_map_ ); |
| load_sf4_map (sf4_map_ ); |
| |
| expression_generator_.init_synthesize_map(); |
| expression_generator_.set_parser(*this); |
| expression_generator_.set_uom(unary_op_map_); |
| expression_generator_.set_bom(binary_op_map_); |
| expression_generator_.set_ibom(inv_binary_op_map_); |
| expression_generator_.set_sf3m(sf3_map_); |
| expression_generator_.set_sf4m(sf4_map_); |
| expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); |
| } |
| |
| ~parser() |
| {} |
| |
| inline void init_precompilation() |
| { |
| if (settings_.collect_variables_enabled()) |
| dec_.collect_variables() = true; |
| |
| if (settings_.collect_functions_enabled()) |
| dec_.collect_functions() = true; |
| |
| if (settings_.collect_assignments_enabled()) |
| dec_.collect_assignments() = true; |
| |
| if (settings_.replacer_enabled()) |
| { |
| symbol_replacer_.clear(); |
| symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number); |
| symbol_replacer_.add_replace("false","0",lexer::token::e_number); |
| helper_assembly_.token_modifier_list.clear(); |
| helper_assembly_.register_modifier(&symbol_replacer_); |
| } |
| |
| if (settings_.commutative_check_enabled()) |
| { |
| for (std::size_t i = 0; i < details::reserved_words_size; ++i) |
| { |
| commutative_inserter_.ignore_symbol(details::reserved_words[i]); |
| } |
| |
| helper_assembly_.token_inserter_list.clear(); |
| helper_assembly_.register_inserter(&commutative_inserter_); |
| } |
| |
| if (settings_.joiner_enabled()) |
| { |
| helper_assembly_.token_joiner_list.clear(); |
| helper_assembly_.register_joiner(&operator_joiner_2_); |
| helper_assembly_.register_joiner(&operator_joiner_3_); |
| } |
| |
| if ( |
| settings_.numeric_check_enabled () || |
| settings_.bracket_check_enabled () || |
| settings_.sequence_check_enabled() |
| ) |
| { |
| helper_assembly_.token_scanner_list.clear(); |
| |
| if (settings_.numeric_check_enabled()) |
| { |
| helper_assembly_.register_scanner(&numeric_checker_); |
| } |
| |
| if (settings_.bracket_check_enabled()) |
| { |
| helper_assembly_.register_scanner(&bracket_checker_); |
| } |
| |
| if (settings_.sequence_check_enabled()) |
| { |
| helper_assembly_.register_scanner(&sequence_validator_); |
| } |
| } |
| } |
| |
| inline bool compile(const std::string& expression_string, expression<T>& expr) |
| { |
| state_ .reset(); |
| error_list_ .clear(); |
| brkcnt_list_ .clear(); |
| synthesis_error_.clear(); |
| sem_ .cleanup(); |
| |
| return_cleanup(); |
| |
| expression_generator_.set_allocator(node_allocator_); |
| |
| if (expression_string.empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| "ERR000 - Empty expression!")); |
| |
| return false; |
| } |
| |
| if (!init(expression_string)) |
| { |
| process_lexer_errors(); |
| return false; |
| } |
| |
| if (lexer().empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| "ERR001 - Empty expression!")); |
| |
| return false; |
| } |
| |
| if (!run_assemblies()) |
| { |
| return false; |
| } |
| |
| symtab_store_.symtab_list_ = expr.get_symbol_table_list(); |
| dec_.clear(); |
| |
| lexer().begin(); |
| |
| next_token(); |
| |
| expression_node_ptr e = parse_corpus(); |
| |
| if ((0 != e) && (token_t::e_eof == current_token().type)) |
| { |
| bool* retinvk_ptr = 0; |
| |
| if (state_.return_stmt_present) |
| { |
| dec_.return_present_ = true; |
| |
| e = expression_generator_ |
| .return_envelope(e,results_context_,retinvk_ptr); |
| } |
| |
| expr.set_expression(e); |
| expr.set_retinvk(retinvk_ptr); |
| |
| register_local_vars(expr); |
| register_return_results(expr); |
| |
| return !(!expr); |
| } |
| else |
| { |
| if (error_list_.empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR002 - Invalid expression encountered")); |
| } |
| |
| dec_.clear (); |
| sem_.cleanup (); |
| return_cleanup(); |
| |
| if ((0 != e) && branch_deletable(e)) |
| { |
| delete e; |
| } |
| |
| return false; |
| } |
| } |
| |
| void process_lexer_errors() |
| { |
| for (std::size_t i = 0; i < lexer().size(); ++i) |
| { |
| if (lexer()[i].is_error()) |
| { |
| std::string diagnostic = "ERR003 - "; |
| |
| switch (lexer()[i].type) |
| { |
| case lexer::token::e_error : diagnostic += "General token error"; |
| break; |
| |
| case lexer::token::e_err_symbol : diagnostic += "Symbol error"; |
| break; |
| |
| case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; |
| break; |
| |
| case lexer::token::e_err_string : diagnostic += "Invalid string token"; |
| break; |
| |
| case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; |
| break; |
| |
| default : diagnostic += "Unknown compiler error"; |
| } |
| |
| set_error( |
| make_error(parser_error::e_lexer, |
| lexer()[i], |
| diagnostic + ": " + lexer()[i].value)); |
| } |
| } |
| } |
| |
| inline bool run_assemblies() |
| { |
| if (settings_.commutative_check_enabled()) |
| { |
| helper_assembly_.run_inserters(lexer()); |
| } |
| |
| if (settings_.joiner_enabled()) |
| { |
| helper_assembly_.run_joiners(lexer()); |
| } |
| |
| if (settings_.replacer_enabled()) |
| { |
| helper_assembly_.run_modifiers(lexer()); |
| } |
| |
| if ( |
| settings_.numeric_check_enabled () || |
| settings_.bracket_check_enabled () || |
| settings_.sequence_check_enabled() |
| ) |
| { |
| if (!helper_assembly_.run_scanners(lexer())) |
| { |
| if (helper_assembly_.error_token_scanner) |
| { |
| lexer::helper::bracket_checker* bracket_checker_ptr = 0; |
| lexer::helper::numeric_checker* numeric_checker_ptr = 0; |
| lexer::helper::sequence_validator* sequence_validator_ptr = 0; |
| |
| if (0 != (bracket_checker_ptr = dynamic_cast<lexer::helper::bracket_checker*>(helper_assembly_.error_token_scanner))) |
| { |
| set_error( |
| make_error(parser_error::e_token, |
| bracket_checker_ptr->error_token(), |
| "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); |
| } |
| else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner))) |
| { |
| for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) |
| { |
| lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; |
| |
| set_error( |
| make_error(parser_error::e_token, |
| error_token, |
| "ERR005 - Invalid numeric token: '" + error_token.value + "'")); |
| } |
| |
| if (numeric_checker_ptr->error_count()) |
| { |
| numeric_checker_ptr->clear_errors(); |
| } |
| } |
| else if (0 != (sequence_validator_ptr = dynamic_cast<lexer::helper::sequence_validator*>(helper_assembly_.error_token_scanner))) |
| { |
| for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) |
| { |
| std::pair<lexer::token,lexer::token> error_token = sequence_validator_ptr->error(i); |
| |
| set_error( |
| make_error(parser_error::e_token, |
| error_token.first, |
| "ERR006 - Invalid token sequence: '" + |
| error_token.first.value + "' and '" + |
| error_token.second.value + "'")); |
| } |
| |
| if (sequence_validator_ptr->error_count()) |
| { |
| sequence_validator_ptr->clear_errors(); |
| } |
| } |
| } |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| inline settings_store& settings() |
| { |
| return settings_; |
| } |
| |
| inline parser_error::type get_error(const std::size_t& index) |
| { |
| if (index < error_list_.size()) |
| return error_list_[index]; |
| else |
| throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); |
| } |
| |
| inline std::string error() const |
| { |
| if (!error_list_.empty()) |
| { |
| return error_list_[0].diagnostic; |
| } |
| else |
| return std::string("No Error"); |
| } |
| |
| inline std::size_t error_count() const |
| { |
| return error_list_.size(); |
| } |
| |
| inline dependent_entity_collector& dec() |
| { |
| return dec_; |
| } |
| |
| inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) |
| { |
| if (!settings_.replacer_enabled()) |
| return false; |
| else if (details::is_reserved_word(old_symbol)) |
| return false; |
| else |
| return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); |
| } |
| |
| inline bool remove_replace_symbol(const std::string& symbol) |
| { |
| if (!settings_.replacer_enabled()) |
| return false; |
| else if (details::is_reserved_word(symbol)) |
| return false; |
| else |
| return symbol_replacer_.remove(symbol); |
| } |
| |
| inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast<unknown_symbol_resolver*>(0)) |
| { |
| resolve_unknown_symbol_ = true; |
| |
| if (usr) |
| unknown_symbol_resolver_ = usr; |
| else |
| unknown_symbol_resolver_ = &default_usr_; |
| } |
| |
| inline void disable_unknown_symbol_resolver() |
| { |
| resolve_unknown_symbol_ = false; |
| unknown_symbol_resolver_ = &default_usr_; |
| } |
| |
| private: |
| |
| inline bool valid_base_operation(const std::string& symbol) |
| { |
| const std::size_t length = symbol.size(); |
| |
| if ( |
| (length < 3) || // Shortest base op symbol length |
| (length > 9) // Longest base op symbol length |
| ) |
| return false; |
| else |
| return settings_.function_enabled(symbol) && |
| (base_ops_map_.end() != base_ops_map_.find(symbol)); |
| } |
| |
| inline bool valid_vararg_operation(const std::string& symbol) |
| { |
| static const std::string s_sum = "sum" ; |
| static const std::string s_mul = "mul" ; |
| static const std::string s_avg = "avg" ; |
| static const std::string s_min = "min" ; |
| static const std::string s_max = "max" ; |
| static const std::string s_mand = "mand"; |
| static const std::string s_mor = "mor" ; |
| static const std::string s_multi = "~" ; |
| static const std::string s_mswitch = "[*]" ; |
| |
| return |
| ( |
| details::imatch(symbol,s_sum ) || |
| details::imatch(symbol,s_mul ) || |
| details::imatch(symbol,s_avg ) || |
| details::imatch(symbol,s_min ) || |
| details::imatch(symbol,s_max ) || |
| details::imatch(symbol,s_mand ) || |
| details::imatch(symbol,s_mor ) || |
| details::imatch(symbol,s_multi ) || |
| details::imatch(symbol,s_mswitch) |
| ) && |
| settings_.function_enabled(symbol); |
| } |
| |
| bool is_invalid_arithmetic_operation(const details::operator_type operation) |
| { |
| return settings_.arithmetic_disabled(operation); |
| } |
| |
| bool is_invalid_assignment_operation(const details::operator_type operation) |
| { |
| return settings_.assignment_disabled(operation); |
| } |
| |
| bool is_invalid_inequality_operation(const details::operator_type operation) |
| { |
| return settings_.inequality_disabled(operation); |
| } |
| |
| #ifdef exprtk_enable_debugging |
| inline void next_token() |
| { |
| std::string ct_str = current_token().value; |
| parser_helper::next_token(); |
| std::string depth(2 * state_.scope_depth,' '); |
| exprtk_debug(("%s" |
| "prev[%s] --> curr[%s]\n", |
| depth.c_str(), |
| ct_str.c_str(), |
| current_token().value.c_str())); |
| } |
| #endif |
| |
| inline expression_node_ptr parse_corpus() |
| { |
| std::vector<expression_node_ptr> arg_list; |
| std::vector<bool> side_effect_list; |
| |
| expression_node_ptr result = error_node(); |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| lexer::token begin_token; |
| lexer::token end_token; |
| |
| for ( ; ; ) |
| { |
| state_.side_effect_present = false; |
| |
| begin_token = current_token(); |
| |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| { |
| if (error_list_.empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR007 - Invalid expression encountered")); |
| } |
| |
| return error_node(); |
| } |
| else |
| { |
| arg_list.push_back(arg); |
| |
| side_effect_list.push_back(state_.side_effect_present); |
| |
| end_token = current_token(); |
| |
| std::string sub_expr = construct_subexpr(begin_token,end_token); |
| |
| exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", |
| static_cast<int>(arg_list.size() - 1), |
| sub_expr.c_str())); |
| |
| exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", |
| static_cast<int>(arg_list.size() - 1), |
| state_.side_effect_present ? "true" : "false")); |
| |
| exprtk_debug(("-------------------------------------------------\n")); |
| } |
| |
| if (lexer().finished()) |
| break; |
| else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) |
| { |
| if (lexer().finished()) |
| break; |
| else |
| next_token(); |
| } |
| } |
| |
| if ( |
| !arg_list.empty() && |
| is_return_node(arg_list.back()) |
| ) |
| { |
| dec_.final_stmt_return_ = true; |
| } |
| |
| result = simplify(arg_list,side_effect_list); |
| |
| sdd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) |
| { |
| std::string result = lexer().substr(begin_token.position,end_token.position); |
| |
| for (std::size_t i = 0; i < result.size(); ++i) |
| { |
| if (details::is_whitespace(result[i])) result[i] = ' '; |
| } |
| |
| return result; |
| } |
| |
| static const precedence_level default_precedence = e_level00; |
| |
| struct state_t |
| { |
| inline void set(const precedence_level& l, |
| const precedence_level& r, |
| const details::operator_type& o) |
| { |
| left = l; |
| right = r; |
| operation = o; |
| } |
| |
| inline void reset() |
| { |
| left = e_level00; |
| right = e_level00; |
| operation = details::e_default; |
| } |
| |
| precedence_level left; |
| precedence_level right; |
| details::operator_type operation; |
| }; |
| |
| inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) |
| { |
| expression_node_ptr expression = parse_branch(precedence); |
| |
| if (0 == expression) |
| { |
| return error_node(); |
| } |
| |
| bool break_loop = false; |
| |
| state_t current_state; |
| |
| for ( ; ; ) |
| { |
| current_state.reset(); |
| |
| switch (current_token().type) |
| { |
| case token_t::e_assign : current_state.set(e_level00,e_level00,details::e_assign); break; |
| case token_t::e_addass : current_state.set(e_level00,e_level00,details::e_addass); break; |
| case token_t::e_subass : current_state.set(e_level00,e_level00,details::e_subass); break; |
| case token_t::e_mulass : current_state.set(e_level00,e_level00,details::e_mulass); break; |
| case token_t::e_divass : current_state.set(e_level00,e_level00,details::e_divass); break; |
| case token_t::e_modass : current_state.set(e_level00,e_level00,details::e_modass); break; |
| case token_t::e_swap : current_state.set(e_level00,e_level00,details::e_swap ); break; |
| case token_t::e_lt : current_state.set(e_level05,e_level06,details:: e_lt); break; |
| case token_t::e_lte : current_state.set(e_level05,e_level06,details:: e_lte); break; |
| case token_t::e_eq : current_state.set(e_level05,e_level06,details:: e_eq); break; |
| case token_t::e_ne : current_state.set(e_level05,e_level06,details:: e_ne); break; |
| case token_t::e_gte : current_state.set(e_level05,e_level06,details:: e_gte); break; |
| case token_t::e_gt : current_state.set(e_level05,e_level06,details:: e_gt); break; |
| case token_t::e_add : current_state.set(e_level07,e_level08,details:: e_add); break; |
| case token_t::e_sub : current_state.set(e_level07,e_level08,details:: e_sub); break; |
| case token_t::e_div : current_state.set(e_level10,e_level11,details:: e_div); break; |
| case token_t::e_mul : current_state.set(e_level10,e_level11,details:: e_mul); break; |
| case token_t::e_mod : current_state.set(e_level10,e_level11,details:: e_mod); break; |
| case token_t::e_pow : current_state.set(e_level12,e_level12,details:: e_pow); break; |
| default : if (token_t::e_symbol == current_token().type) |
| { |
| static const std::string s_and = "and"; |
| static const std::string s_nand = "nand"; |
| static const std::string s_or = "or"; |
| static const std::string s_nor = "nor"; |
| static const std::string s_xor = "xor"; |
| static const std::string s_xnor = "xnor"; |
| static const std::string s_in = "in"; |
| static const std::string s_like = "like"; |
| static const std::string s_ilike = "ilike"; |
| static const std::string s_and1 = "&"; |
| static const std::string s_or1 = "|"; |
| |
| if (details::imatch(current_token().value,s_and)) |
| { |
| current_state.set(e_level03,e_level04,details::e_and); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_and1)) |
| { |
| #ifndef exprtk_disable_sc_andor |
| current_state.set(e_level03,e_level04,details::e_scand); |
| #else |
| current_state.set(e_level03,e_level04,details::e_and); |
| #endif |
| break; |
| } |
| else if (details::imatch(current_token().value,s_nand)) |
| { |
| current_state.set(e_level03,e_level04,details::e_nand); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_or)) |
| { |
| current_state.set(e_level01,e_level02,details::e_or); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_or1)) |
| { |
| #ifndef exprtk_disable_sc_andor |
| current_state.set(e_level01,e_level02,details::e_scor); |
| #else |
| current_state.set(e_level01,e_level02,details::e_or); |
| #endif |
| break; |
| } |
| else if (details::imatch(current_token().value,s_nor)) |
| { |
| current_state.set(e_level01,e_level02,details::e_nor); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_xor)) |
| { |
| current_state.set(e_level01,e_level02,details::e_xor); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_xnor)) |
| { |
| current_state.set(e_level01,e_level02,details::e_xnor); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_in)) |
| { |
| current_state.set(e_level04,e_level04,details::e_in); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_like)) |
| { |
| current_state.set(e_level04,e_level04,details::e_like); |
| break; |
| } |
| else if (details::imatch(current_token().value,s_ilike)) |
| { |
| current_state.set(e_level04,e_level04,details::e_ilike); |
| break; |
| } |
| } |
| |
| break_loop = true; |
| } |
| |
| if (break_loop) |
| { |
| parse_pending_string_rangesize(expression); |
| break; |
| } |
| else if (current_state.left < precedence) |
| break; |
| |
| lexer::token prev_token = current_token(); |
| |
| next_token(); |
| |
| expression_node_ptr right_branch = error_node(); |
| expression_node_ptr new_expression = error_node(); |
| |
| if (is_invalid_arithmetic_operation(current_state.operation)) |
| { |
| free_node(node_allocator_,expression); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'")); |
| |
| return error_node(); |
| } |
| else if (is_invalid_inequality_operation(current_state.operation)) |
| { |
| free_node(node_allocator_,expression); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'")); |
| |
| return error_node(); |
| } |
| else if (is_invalid_assignment_operation(current_state.operation)) |
| { |
| free_node(node_allocator_,expression); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'")); |
| |
| return error_node(); |
| } |
| |
| if (0 != (right_branch = parse_expression(current_state.right))) |
| { |
| if ( |
| details::is_return_node( expression) || |
| details::is_return_node(right_branch) |
| ) |
| { |
| free_node(node_allocator_, expression); |
| free_node(node_allocator_,right_branch); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| "ERR011 - Return statements cannot be part of sub-expressions")); |
| |
| return error_node(); |
| } |
| |
| new_expression = expression_generator_ |
| ( |
| current_state.operation, |
| expression, |
| right_branch |
| ); |
| } |
| |
| if (0 == new_expression) |
| { |
| if (error_list_.empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| !synthesis_error_.empty() ? |
| synthesis_error_ : |
| "ERR012 - General parsing error at token: '" + prev_token.value + "'")); |
| } |
| |
| free_node(node_allocator_,expression); |
| |
| return error_node(); |
| } |
| else |
| { |
| if ( |
| token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && |
| (precedence == e_level00) |
| ) |
| { |
| expression = parse_ternary_conditional_statement(new_expression); |
| } |
| else |
| expression = new_expression; |
| |
| parse_pending_string_rangesize(expression); |
| } |
| } |
| |
| return expression; |
| } |
| |
| bool simplify_unary_negation_branch(expression_node_ptr& node) |
| { |
| { |
| typedef details::unary_branch_node<T,details::neg_op<T> > ubn_t; |
| ubn_t* n = dynamic_cast<ubn_t*>(node); |
| |
| if (n) |
| { |
| expression_node_ptr un_r = n->branch(0); |
| n->release(); |
| free_node(node_allocator_,node); |
| node = un_r; |
| |
| return true; |
| } |
| } |
| |
| { |
| typedef details::unary_variable_node<T,details::neg_op<T> > uvn_t; |
| |
| uvn_t* n = dynamic_cast<uvn_t*>(node); |
| |
| if (n) |
| { |
| const T& v = n->v(); |
| expression_node_ptr return_node = error_node(); |
| |
| if ( |
| (0 != (return_node = symtab_store_.get_variable(v))) || |
| (0 != (return_node = sem_ .get_variable(v))) |
| ) |
| { |
| free_node(node_allocator_,node); |
| node = return_node; |
| |
| return true; |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR013 - Failed to find variable node in symbol table")); |
| |
| free_node(node_allocator_,node); |
| |
| return false; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| static inline expression_node_ptr error_node() |
| { |
| return reinterpret_cast<expression_node_ptr>(0); |
| } |
| |
| template <typename Type, std::size_t N> |
| struct scoped_delete |
| { |
| typedef Type* ptr_t; |
| |
| scoped_delete(parser<T>& pr, ptr_t& p) |
| : delete_ptr(true), |
| parser_(pr), |
| p_(&p) |
| {} |
| |
| scoped_delete(parser<T>& pr, ptr_t (&p)[N]) |
| : delete_ptr(true), |
| parser_(pr), |
| p_(&p[0]) |
| {} |
| |
| ~scoped_delete() |
| { |
| if (delete_ptr) |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| free_node(parser_.node_allocator_,p_[i]); |
| } |
| } |
| } |
| |
| bool delete_ptr; |
| parser<T>& parser_; |
| ptr_t* p_; |
| |
| private: |
| |
| scoped_delete<Type,N>& operator=(const scoped_delete<Type,N>&); |
| }; |
| |
| template <typename Type> |
| struct scoped_deq_delete |
| { |
| typedef Type* ptr_t; |
| |
| scoped_deq_delete(parser<T>& pr, std::deque<ptr_t>& deq) |
| : delete_ptr(true), |
| parser_(pr), |
| deq_(deq) |
| {} |
| |
| ~scoped_deq_delete() |
| { |
| if (delete_ptr && !deq_.empty()) |
| { |
| for (std::size_t i = 0; i < deq_.size(); ++i) |
| { |
| free_node(parser_.node_allocator_,deq_[i]); |
| } |
| |
| deq_.clear(); |
| } |
| } |
| |
| bool delete_ptr; |
| parser<T>& parser_; |
| std::deque<ptr_t>& deq_; |
| |
| private: |
| |
| scoped_deq_delete<Type>& operator=(const scoped_deq_delete<Type>&); |
| }; |
| |
| template <typename Type> |
| struct scoped_vec_delete |
| { |
| typedef Type* ptr_t; |
| |
| scoped_vec_delete(parser<T>& pr, std::vector<ptr_t>& vec) |
| : delete_ptr(true), |
| parser_(pr), |
| vec_(vec) |
| {} |
| |
| ~scoped_vec_delete() |
| { |
| if (delete_ptr && !vec_.empty()) |
| { |
| for (std::size_t i = 0; i < vec_.size(); ++i) |
| { |
| free_node(parser_.node_allocator_,vec_[i]); |
| } |
| |
| vec_.clear(); |
| } |
| } |
| |
| bool delete_ptr; |
| parser<T>& parser_; |
| std::vector<ptr_t>& vec_; |
| |
| private: |
| |
| scoped_vec_delete<Type>& operator=(const scoped_vec_delete<Type>&); |
| }; |
| |
| struct scoped_bool_negator |
| { |
| scoped_bool_negator(bool& bb) |
| : b(bb) |
| { b = !b; } |
| |
| ~scoped_bool_negator() |
| { b = !b; } |
| |
| bool& b; |
| }; |
| |
| struct scoped_bool_or_restorer |
| { |
| scoped_bool_or_restorer(bool& bb) |
| : b(bb), |
| original_value_(bb) |
| {} |
| |
| ~scoped_bool_or_restorer() |
| { |
| b = b || original_value_; |
| } |
| |
| bool& b; |
| bool original_value_; |
| }; |
| |
| inline expression_node_ptr parse_function_invocation(ifunction<T>* function, const std::string& function_name) |
| { |
| expression_node_ptr func_node = reinterpret_cast<expression_node_ptr>(0); |
| |
| switch (function->param_count) |
| { |
| case 0 : func_node = parse_function_call_0 (function,function_name); break; |
| case 1 : func_node = parse_function_call< 1>(function,function_name); break; |
| case 2 : func_node = parse_function_call< 2>(function,function_name); break; |
| case 3 : func_node = parse_function_call< 3>(function,function_name); break; |
| case 4 : func_node = parse_function_call< 4>(function,function_name); break; |
| case 5 : func_node = parse_function_call< 5>(function,function_name); break; |
| case 6 : func_node = parse_function_call< 6>(function,function_name); break; |
| case 7 : func_node = parse_function_call< 7>(function,function_name); break; |
| case 8 : func_node = parse_function_call< 8>(function,function_name); break; |
| case 9 : func_node = parse_function_call< 9>(function,function_name); break; |
| case 10 : func_node = parse_function_call<10>(function,function_name); break; |
| case 11 : func_node = parse_function_call<11>(function,function_name); break; |
| case 12 : func_node = parse_function_call<12>(function,function_name); break; |
| case 13 : func_node = parse_function_call<13>(function,function_name); break; |
| case 14 : func_node = parse_function_call<14>(function,function_name); break; |
| case 15 : func_node = parse_function_call<15>(function,function_name); break; |
| case 16 : func_node = parse_function_call<16>(function,function_name); break; |
| case 17 : func_node = parse_function_call<17>(function,function_name); break; |
| case 18 : func_node = parse_function_call<18>(function,function_name); break; |
| case 19 : func_node = parse_function_call<19>(function,function_name); break; |
| case 20 : func_node = parse_function_call<20>(function,function_name); break; |
| default : { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR014 - Invalid number of parameters for function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| } |
| |
| if (func_node) |
| return func_node; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR015 - Failed to generate call to function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| } |
| |
| template <std::size_t NumberofParameters> |
| inline expression_node_ptr parse_function_call(ifunction<T>* function, const std::string& function_name) |
| { |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable: 4127) |
| #endif |
| if (0 == NumberofParameters) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); |
| |
| return error_node(); |
| } |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| |
| expression_node_ptr branch[NumberofParameters]; |
| expression_node_ptr result = error_node(); |
| |
| std::fill_n(branch,NumberofParameters,reinterpret_cast<expression_node_ptr>(0)); |
| scoped_delete<expression_node_t,NumberofParameters> sd(*this,branch); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR017 - Expecting argument list for function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| |
| for (int i = 0; i < static_cast<int>(NumberofParameters); ++i) |
| { |
| branch[i] = parse_expression(); |
| |
| if (0 == branch[i]) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR018 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| else if (i < static_cast<int>(NumberofParameters - 1)) |
| { |
| if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR019 - Invalid number of arguments for function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR020 - Invalid number of arguments for function: '" + function_name + "'")); |
| |
| return error_node(); |
| } |
| else |
| result = expression_generator_.function(function,branch); |
| |
| sd.delete_ptr = false; |
| |
| return result; |
| } |
| |
| inline expression_node_ptr parse_function_call_0(ifunction<T>* function, const std::string& function_name) |
| { |
| expression_node_ptr result = expression_generator_.function(function); |
| |
| state_.side_effect_present = function->has_side_effects(); |
| |
| next_token(); |
| |
| if ( |
| token_is(token_t::e_lbracket) && |
| !token_is(token_t::e_rbracket) |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR021 - Expecting '()' to proceed call to function: '" + function_name + "'")); |
| |
| free_node(node_allocator_,result); |
| |
| return error_node(); |
| } |
| else |
| return result; |
| } |
| |
| template <std::size_t MaxNumberofParameters> |
| inline int parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters]) |
| { |
| std::fill_n(param_list,MaxNumberofParameters,reinterpret_cast<expression_node_ptr>(0)); |
| |
| scoped_delete<expression_node_t,MaxNumberofParameters> sd(*this,param_list); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR022 - Expected a '(' at start of function call, instead got: '" + current_token().value + "'")); |
| |
| return 0; |
| } |
| |
| int param_index = 0; |
| |
| for (; param_index < static_cast<int>(MaxNumberofParameters); ++param_index) |
| { |
| param_list[param_index] = parse_expression(); |
| |
| if (0 == param_list[param_index]) |
| return 0; |
| else if (token_is(token_t::e_rbracket)) |
| break; |
| else if (token_is(token_t::e_comma)) |
| continue; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR023 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'")); |
| |
| return 0; |
| } |
| } |
| |
| sd.delete_ptr = false; |
| |
| return (param_index + 1); |
| } |
| |
| inline expression_node_ptr parse_base_operation() |
| { |
| typedef std::pair<base_ops_map_t::iterator,base_ops_map_t::iterator> map_range_t; |
| |
| const std::string operation_name = current_token().value; |
| map_range_t itr_range = base_ops_map_.equal_range(operation_name); |
| |
| if (0 == std::distance(itr_range.first,itr_range.second)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR024 - No entry found for base operation: " + operation_name)); |
| |
| return error_node(); |
| } |
| |
| static const std::size_t MaxNumberofParameters = 4; |
| expression_node_ptr param_list[MaxNumberofParameters] = {0}; |
| |
| std::size_t parameter_count = parse_base_function_call(param_list); |
| |
| if (0 == parameter_count) |
| { |
| return error_node(); |
| } |
| else if (parameter_count <= MaxNumberofParameters) |
| { |
| for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) |
| { |
| details::base_operation_t& operation = itr->second; |
| |
| if (operation.num_params == parameter_count) |
| { |
| switch (parameter_count) |
| { |
| #define base_opr_case(N) \ |
| case N : { \ |
| expression_node_ptr pl##N[N] = {0}; \ |
| std::copy(param_list,param_list + N,pl##N); \ |
| lodge_symbol(operation_name,e_st_function); \ |
| return expression_generator_(operation.type,pl##N); \ |
| } \ |
| |
| base_opr_case(1) |
| base_opr_case(2) |
| base_opr_case(3) |
| base_opr_case(4) |
| #undef base_opr_case |
| } |
| } |
| } |
| } |
| |
| for (std::size_t i = 0; i < MaxNumberofParameters; ++i) |
| { |
| free_node(node_allocator_,param_list[i]); |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR025 - Invalid number of parameters for call to function: '" + operation_name + "'")); |
| |
| return error_node(); |
| } |
| |
| inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) |
| { |
| // Parse: [if][(][condition][,][consequent][,][alternative][)] |
| |
| expression_node_ptr consequent = error_node(); |
| expression_node_ptr alternative = error_node(); |
| |
| bool result = true; |
| |
| if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR026 - Expected ',' between if-statement condition and consequent")); |
| result = false; |
| } |
| else if (0 == (consequent = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR027 - Failed to parse consequent for if-statement")); |
| result = false; |
| } |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR028 - Expected ',' between if-statement consequent and alternative")); |
| result = false; |
| } |
| else if (0 == (alternative = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR029 - Failed to parse alternative for if-statement")); |
| result = false; |
| } |
| else if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR030 - Expected ')' at the end of if-statement")); |
| result = false; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| if (result) |
| { |
| const bool consq_is_str = is_generally_string_node( consequent); |
| const bool alter_is_str = is_generally_string_node(alternative); |
| |
| if (consq_is_str || alter_is_str) |
| { |
| if (consq_is_str && alter_is_str) |
| { |
| return expression_generator_ |
| .conditional_string(condition,consequent,alternative); |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR031 - Return types of ternary if-statement differ")); |
| |
| result = false; |
| } |
| } |
| #endif |
| |
| if (!result) |
| { |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_, consequent); |
| free_node(node_allocator_,alternative); |
| |
| return error_node(); |
| } |
| else |
| return expression_generator_ |
| .conditional(condition,consequent,alternative); |
| } |
| |
| inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) |
| { |
| expression_node_ptr consequent = error_node(); |
| expression_node_ptr alternative = error_node(); |
| |
| bool result = true; |
| |
| if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) |
| { |
| if (0 == (consequent = parse_multi_sequence("if-statement-01"))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR032 - Failed to parse body of consequent for if-statement")); |
| result = false; |
| } |
| } |
| else |
| { |
| if ( |
| settings_.commutative_check_enabled() && |
| token_is(token_t::e_mul,prsrhlpr_t::e_hold) |
| ) |
| { |
| next_token(); |
| } |
| |
| if (0 != (consequent = parse_expression())) |
| { |
| if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR033 - Expected ';' at the end of the consequent for if-statement")); |
| result = false; |
| } |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR034 - Failed to parse body of consequent for if-statement")); |
| result = false; |
| } |
| } |
| |
| if (result) |
| { |
| if (details::imatch(current_token().value,"else")) |
| { |
| next_token(); |
| |
| if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) |
| { |
| if (0 == (alternative = parse_multi_sequence("else-statement-01"))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR035 - Failed to parse body of the 'else' for if-statement")); |
| result = false; |
| } |
| } |
| else if (details::imatch(current_token().value,"if")) |
| { |
| if (0 == (alternative = parse_conditional_statement())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR036 - Failed to parse body of if-else statement")); |
| result = false; |
| } |
| } |
| else if (0 != (alternative = parse_expression())) |
| { |
| if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR037 - Expected ';' at the end of the 'else-if' for the if-statement")); |
| result = false; |
| } |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR038 - Failed to parse body of the 'else' for if-statement")); |
| result = false; |
| } |
| } |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| if (result) |
| { |
| const bool consq_is_str = is_generally_string_node( consequent); |
| const bool alter_is_str = is_generally_string_node(alternative); |
| |
| if (consq_is_str || alter_is_str) |
| { |
| if (consq_is_str && alter_is_str) |
| { |
| return expression_generator_ |
| .conditional_string(condition,consequent,alternative); |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR039 - Return types of ternary if-statement differ")); |
| |
| result = false; |
| } |
| } |
| #endif |
| |
| if (!result) |
| { |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_, consequent); |
| free_node(node_allocator_,alternative); |
| |
| return error_node(); |
| } |
| else |
| return expression_generator_ |
| .conditional(condition,consequent,alternative); |
| } |
| |
| inline expression_node_ptr parse_conditional_statement() |
| { |
| expression_node_ptr condition = error_node(); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR040 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'")); |
| |
| return error_node(); |
| } |
| else if (0 == (condition = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR041 - Failed to parse condition for if-statement")); |
| |
| return error_node(); |
| } |
| else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) |
| { |
| // if (x,y,z) |
| return parse_conditional_statement_01(condition); |
| } |
| else if (token_is(token_t::e_rbracket)) |
| { |
| // 00. if (x) y; |
| // 01. if (x) y; else z; |
| // 02. if (x) y; else {z0; ... zn;} |
| // 03. if (x) y; else if (z) w; |
| // 04. if (x) y; else if (z) w; else u; |
| // 05. if (x) y; else if (z) w; else {u0; ... un;} |
| // 06. if (x) y; else if (z) {w0; ... wn;} |
| // 07. if (x) {y0; ... yn;} |
| // 08. if (x) {y0; ... yn;} else z; |
| // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; |
| // 10. if (x) {y0; ... yn;} else if (z) w; |
| // 11. if (x) {y0; ... yn;} else if (z) w; else u; |
| // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} |
| // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} |
| return parse_conditional_statement_02(condition); |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR042 - Invalid if-statement")); |
| |
| free_node(node_allocator_,condition); |
| |
| return error_node(); |
| } |
| |
| inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) |
| { |
| // Parse: [condition][?][consequent][:][alternative] |
| expression_node_ptr consequent = error_node(); |
| expression_node_ptr alternative = error_node(); |
| |
| bool result = true; |
| |
| if (0 == condition) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR043 - Encountered invalid condition branch for ternary if-statement")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_ternary)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR044 - Expected '?' after condition of ternary if-statement")); |
| |
| result = false; |
| } |
| else if (0 == (consequent = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR045 - Failed to parse consequent for ternary if-statement")); |
| |
| result = false; |
| } |
| else if (!token_is(token_t::e_colon)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR046 - Expected ':' between ternary if-statement consequent and alternative")); |
| |
| result = false; |
| } |
| else if (0 == (alternative = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR047 - Failed to parse alternative for ternary if-statement")); |
| |
| result = false; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| if (result) |
| { |
| const bool consq_is_str = is_generally_string_node( consequent); |
| const bool alter_is_str = is_generally_string_node(alternative); |
| |
| if (consq_is_str || alter_is_str) |
| { |
| if (consq_is_str && alter_is_str) |
| { |
| return expression_generator_ |
| .conditional_string(condition,consequent,alternative); |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR048 - Return types of ternary if-statement differ")); |
| |
| result = false; |
| } |
| } |
| #endif |
| |
| if (!result) |
| { |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_, consequent); |
| free_node(node_allocator_,alternative); |
| |
| return error_node(); |
| } |
| else |
| return expression_generator_ |
| .conditional(condition,consequent,alternative); |
| } |
| |
| inline expression_node_ptr parse_while_loop() |
| { |
| // Parse: [while][(][test expr][)][{][expression][}] |
| expression_node_ptr condition = error_node(); |
| expression_node_ptr branch = error_node(); |
| expression_node_ptr result_node = error_node(); |
| |
| bool result = true; |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR049 - Expected '(' at start of while-loop condition statement")); |
| |
| return error_node(); |
| } |
| else if (0 == (condition = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR050 - Failed to parse condition for while-loop")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR051 - Expected ')' at end of while-loop condition statement")); |
| result = false; |
| } |
| |
| brkcnt_list_.push_front(false); |
| |
| if (result) |
| { |
| if (0 == (branch = parse_multi_sequence("while-loop"))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR052 - Failed to parse body of while-loop")); |
| result = false; |
| } |
| else if (0 == (result_node = expression_generator_.while_loop(condition, |
| branch, |
| brkcnt_list_.front()))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR053 - Failed to synthesize while-loop")); |
| result = false; |
| } |
| } |
| |
| if (!result) |
| { |
| free_node(node_allocator_, branch); |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_,result_node); |
| |
| brkcnt_list_.pop_front(); |
| |
| return error_node(); |
| } |
| else |
| return result_node; |
| } |
| |
| inline expression_node_ptr parse_repeat_until_loop() |
| { |
| // Parse: [repeat][{][expression][}][until][(][test expr][)] |
| expression_node_ptr condition = error_node(); |
| expression_node_ptr branch = error_node(); |
| next_token(); |
| |
| std::vector<expression_node_ptr> arg_list; |
| std::vector<bool> side_effect_list; |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| brkcnt_list_.push_front(false); |
| |
| if (details::imatch(current_token().value,"until")) |
| { |
| next_token(); |
| branch = node_allocator_.allocate<details::null_node<T> >(); |
| } |
| else |
| { |
| token_t::token_type seperator = token_t::e_eof; |
| |
| scope_handler sh(*this); |
| |
| scoped_bool_or_restorer sbr(state_.side_effect_present); |
| |
| for ( ; ; ) |
| { |
| state_.side_effect_present = false; |
| |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| else |
| { |
| arg_list.push_back(arg); |
| side_effect_list.push_back(state_.side_effect_present); |
| } |
| |
| if (details::imatch(current_token().value,"until")) |
| { |
| next_token(); |
| break; |
| } |
| |
| bool is_next_until = peek_token_is(token_t::e_symbol) && |
| peek_token_is("until"); |
| |
| if (!token_is(seperator) && is_next_until) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR054 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop")); |
| |
| return error_node(); |
| } |
| |
| if (details::imatch(current_token().value,"until")) |
| { |
| next_token(); |
| break; |
| } |
| } |
| |
| branch = simplify(arg_list,side_effect_list); |
| |
| sdd.delete_ptr = (0 == branch); |
| |
| if (sdd.delete_ptr) |
| { |
| brkcnt_list_.pop_front(); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR055 - Failed to parse body of repeat until loop")); |
| |
| return error_node(); |
| } |
| } |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| brkcnt_list_.pop_front(); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR056 - Expected '(' before condition statement of repeat until loop")); |
| |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (0 == (condition = parse_expression())) |
| { |
| brkcnt_list_.pop_front(); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR057 - Failed to parse condition for repeat until loop")); |
| |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR058 - Expected ')' after condition of repeat until loop")); |
| |
| free_node(node_allocator_, branch); |
| free_node(node_allocator_, condition); |
| |
| brkcnt_list_.pop_front(); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr result; |
| |
| result = expression_generator_ |
| .repeat_until_loop(condition,branch,brkcnt_list_.front()); |
| |
| if (0 == result) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR059 - Failed to synthesize repeat until loop")); |
| |
| free_node(node_allocator_, condition); |
| brkcnt_list_.pop_front(); |
| |
| return error_node(); |
| } |
| else |
| { |
| brkcnt_list_.pop_front(); |
| return result; |
| } |
| } |
| |
| inline expression_node_ptr parse_for_loop() |
| { |
| expression_node_ptr initialiser = error_node(); |
| expression_node_ptr condition = error_node(); |
| expression_node_ptr incrementor = error_node(); |
| expression_node_ptr loop_body = error_node(); |
| |
| scope_element* se = 0; |
| bool result = true; |
| std::string loop_counter_symbol; |
| |
| next_token(); |
| |
| scope_handler sh(*this); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR060 - Expected '(' at start of for-loop")); |
| |
| return error_node(); |
| } |
| |
| if (!token_is(token_t::e_eof)) |
| { |
| if ( |
| !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && |
| details::imatch(current_token().value,"var") |
| ) |
| { |
| next_token(); |
| |
| if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR061 - Expected a variable at the start of initialiser section of for-loop")); |
| |
| return error_node(); |
| } |
| else if (!peek_token_is(token_t::e_assign)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR062 - Expected variable assignment of initialiser section of for-loop")); |
| |
| return error_node(); |
| } |
| |
| loop_counter_symbol = current_token().value; |
| |
| se = &sem_.get_element(loop_counter_symbol); |
| |
| if ((se->name == loop_counter_symbol) && se->active) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR063 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); |
| |
| return error_node(); |
| } |
| else if (!symtab_store_.is_variable(loop_counter_symbol)) |
| { |
| if ( |
| !se->active && |
| (se->name == loop_counter_symbol) && |
| (se->type == scope_element::e_variable) |
| ) |
| { |
| se->active = true; |
| se->ref_count++; |
| } |
| else |
| { |
| scope_element nse; |
| nse.name = loop_counter_symbol; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_variable; |
| nse.depth = state_.scope_depth; |
| nse.data = new T(T(0)); |
| nse.var_node = node_allocator_.allocate<variable_node_t>(*(T*)(nse.data)); |
| |
| if (!sem_.add_element(nse)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR064 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); |
| |
| sem_.free_element(nse); |
| |
| result = false; |
| } |
| else |
| { |
| exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); |
| |
| state_.activate_side_effect("parse_for_loop()"); |
| } |
| } |
| } |
| } |
| |
| if (0 == (initialiser = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR065 - Failed to parse initialiser of for-loop")); |
| result = false; |
| } |
| else if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR066 - Expected ';' after initialiser of for-loop")); |
| result = false; |
| } |
| } |
| |
| if (!token_is(token_t::e_eof)) |
| { |
| if (0 == (condition = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR067 - Failed to parse condition of for-loop")); |
| result = false; |
| } |
| else if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR068 - Expected ';' after condition section of for-loop")); |
| result = false; |
| } |
| } |
| |
| if (!token_is(token_t::e_rbracket)) |
| { |
| if (0 == (incrementor = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR069 - Failed to parse incrementor of for-loop")); |
| result = false; |
| } |
| else if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR070 - Expected ')' after incrementor section of for-loop")); |
| result = false; |
| } |
| } |
| |
| if (result) |
| { |
| brkcnt_list_.push_front(false); |
| |
| if (0 == (loop_body = parse_multi_sequence("for-loop"))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR071 - Failed to parse body of for-loop")); |
| result = false; |
| } |
| } |
| |
| if (!result) |
| { |
| if (se) |
| { |
| se->ref_count--; |
| } |
| |
| sem_.cleanup(); |
| |
| free_node(node_allocator_,initialiser); |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_,incrementor); |
| free_node(node_allocator_, loop_body); |
| |
| if (!brkcnt_list_.empty()) |
| { |
| brkcnt_list_.pop_front(); |
| } |
| |
| return error_node(); |
| } |
| else |
| { |
| expression_node_ptr result_node = |
| expression_generator_.for_loop(initialiser, |
| condition, |
| incrementor, |
| loop_body, |
| brkcnt_list_.front()); |
| brkcnt_list_.pop_front(); |
| |
| return result_node; |
| } |
| } |
| |
| inline expression_node_ptr parse_switch_statement() |
| { |
| std::vector<expression_node_ptr> arg_list; |
| expression_node_ptr result = error_node(); |
| |
| if (!details::imatch(current_token().value,"switch")) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR072 - Expected keyword 'switch'")); |
| |
| return error_node(); |
| } |
| |
| scoped_vec_delete<expression_node_t> svd(*this,arg_list); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lcrlbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR073 - Expected '{' for call to switch statement")); |
| |
| return error_node(); |
| } |
| |
| for ( ; ; ) |
| { |
| if (!details::imatch("case",current_token().value)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR074 - Expected either a 'case' or 'default' statement")); |
| |
| return error_node(); |
| } |
| |
| next_token(); |
| |
| expression_node_ptr condition = parse_expression(); |
| |
| if (0 == condition) |
| return error_node(); |
| else if (!token_is(token_t::e_colon)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR075 - Expected ':' for case of switch statement")); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr consequent = parse_expression(); |
| |
| if (0 == consequent) |
| return error_node(); |
| else if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR076 - Expected ';' at end of case for switch statement")); |
| |
| return error_node(); |
| } |
| |
| // Can we optimise away the case statement? |
| if (is_constant_node(condition) && is_false(condition)) |
| { |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_,consequent); |
| |
| condition = 0; |
| consequent = 0; |
| } |
| else |
| { |
| arg_list.push_back( condition); |
| arg_list.push_back(consequent); |
| } |
| |
| if (details::imatch("default",current_token().value)) |
| { |
| next_token(); |
| if (!token_is(token_t::e_colon)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR077 - Expected ':' for default of switch statement")); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr default_statement = error_node(); |
| |
| if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) |
| default_statement = parse_multi_sequence("switch-default"); |
| else |
| default_statement = parse_expression(); |
| |
| if (0 == default_statement) |
| return error_node(); |
| else if (!token_is(token_t::e_eof)) |
| { |
| free_node(node_allocator_,default_statement); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR078 - Expected ';' at end of default for switch statement")); |
| |
| return error_node(); |
| } |
| |
| arg_list.push_back(default_statement); |
| break; |
| } |
| } |
| |
| if (!token_is(token_t::e_rcrlbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR079 - Expected '}' at end of switch statement")); |
| |
| return error_node(); |
| } |
| |
| result = expression_generator_.switch_statement(arg_list); |
| |
| svd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr parse_multi_switch_statement() |
| { |
| std::vector<expression_node_ptr> arg_list; |
| expression_node_ptr result = error_node(); |
| |
| if (!details::imatch(current_token().value,"[*]")) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR080 - Expected token '[*]'")); |
| |
| return error_node(); |
| } |
| |
| scoped_vec_delete<expression_node_t> svd(*this,arg_list); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lcrlbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR081 - Expected '{' for call to [*] statement")); |
| |
| return error_node(); |
| } |
| |
| for ( ; ; ) |
| { |
| if (!details::imatch("case",current_token().value)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR082 - Expected a 'case' statement for multi-switch")); |
| |
| return error_node(); |
| } |
| |
| next_token(); |
| |
| expression_node_ptr condition = parse_expression(); |
| |
| if (0 == condition) |
| return error_node(); |
| |
| if (!token_is(token_t::e_colon)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR083 - Expected ':' for case of [*] statement")); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr consequent = parse_expression(); |
| |
| if (0 == consequent) |
| return error_node(); |
| |
| if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR084 - Expected ';' at end of case for [*] statement")); |
| |
| return error_node(); |
| } |
| |
| // Can we optimise away the case statement? |
| if (is_constant_node(condition) && is_false(condition)) |
| { |
| free_node(node_allocator_, condition); |
| free_node(node_allocator_,consequent); |
| |
| condition = 0; |
| consequent = 0; |
| } |
| else |
| { |
| arg_list.push_back(condition); |
| arg_list.push_back(consequent); |
| } |
| |
| if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) |
| { |
| break; |
| } |
| } |
| |
| if (!token_is(token_t::e_rcrlbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR085 - Expected '}' at end of [*] statement")); |
| |
| return error_node(); |
| } |
| |
| result = expression_generator_.multi_switch_statement(arg_list); |
| |
| svd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr parse_vararg_function() |
| { |
| std::vector<expression_node_ptr> arg_list; |
| expression_node_ptr result = error_node(); |
| |
| details::operator_type opt_type = details::e_default; |
| const std::string symbol = current_token().value; |
| |
| if (details::imatch(symbol,"~")) |
| { |
| next_token(); |
| return parse_multi_sequence(); |
| } |
| else if (details::imatch(symbol,"[*]")) |
| { |
| return parse_multi_switch_statement(); |
| } |
| else if (details::imatch(symbol,"avg" )) opt_type = details::e_avg; |
| else if (details::imatch(symbol,"mand")) opt_type = details::e_mand; |
| else if (details::imatch(symbol,"max" )) opt_type = details::e_max; |
| else if (details::imatch(symbol,"min" )) opt_type = details::e_min; |
| else if (details::imatch(symbol,"mor" )) opt_type = details::e_mor; |
| else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod; |
| else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR086 - Unsupported vararg function: " + symbol)); |
| |
| return error_node(); |
| } |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| lodge_symbol(symbol,e_st_function); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR087 - Expected '(' for call to vararg function: " + symbol)); |
| |
| return error_node(); |
| } |
| |
| for ( ; ; ) |
| { |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| else |
| arg_list.push_back(arg); |
| |
| if (token_is(token_t::e_rbracket)) |
| break; |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR088 - Expected ',' for call to vararg function: " + symbol)); |
| |
| return error_node(); |
| } |
| } |
| |
| result = expression_generator_.vararg_function(opt_type,arg_list); |
| |
| sdd.delete_ptr = (0 == result); |
| return result; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) |
| { |
| if (!token_is(token_t::e_lsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR089 - Expected '[' as start of string range definition")); |
| |
| free_node(node_allocator_,expression); |
| |
| return error_node(); |
| } |
| else if (token_is(token_t::e_rsqrbracket)) |
| { |
| return node_allocator_.allocate<details::string_size_node<T> >(expression); |
| } |
| |
| range_t rp; |
| |
| if (!parse_range(rp,true)) |
| { |
| free_node(node_allocator_,expression); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr result = expression_generator_(expression,rp); |
| |
| if (0 == result) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR090 - Failed to generate string range node")); |
| |
| free_node(node_allocator_,expression); |
| } |
| |
| rp.clear(); |
| |
| return result; |
| } |
| #else |
| inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) |
| { |
| return error_node(); |
| } |
| #endif |
| |
| inline void parse_pending_string_rangesize(expression_node_ptr& expression) |
| { |
| // Allow no more than 100 range calls, eg: s[][][]...[][] |
| const std::size_t max_rangesize_parses = 100; |
| |
| std::size_t i = 0; |
| |
| while |
| ( |
| (0 != expression) && |
| (i++ < max_rangesize_parses) && |
| error_list_.empty() && |
| is_generally_string_node(expression) && |
| token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) |
| ) |
| { |
| expression = parse_string_range_statement(expression); |
| } |
| } |
| |
| template <typename Allocator1, |
| typename Allocator2, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr simplify(Sequence<expression_node_ptr,Allocator1>& expression_list, |
| Sequence<bool,Allocator2>& side_effect_list) |
| { |
| if (expression_list.empty()) |
| return error_node(); |
| else if (1 == expression_list.size()) |
| return expression_list[0]; |
| |
| Sequence<expression_node_ptr,Allocator1> tmp_expression_list; |
| |
| bool return_node_present = false; |
| |
| for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) |
| { |
| if (is_variable_node(expression_list[i])) |
| continue; |
| else if ( |
| is_return_node (expression_list[i]) || |
| is_break_node (expression_list[i]) || |
| is_continue_node(expression_list[i]) |
| ) |
| { |
| tmp_expression_list.push_back(expression_list[i]); |
| |
| // Remove all subexpressions after first short-circuit |
| // node has been encountered. |
| |
| for (std::size_t j = i + 1; j < expression_list.size(); ++j) |
| { |
| free_node(node_allocator_,expression_list[j]); |
| } |
| |
| return_node_present = true; |
| |
| break; |
| } |
| else if ( |
| is_constant_node(expression_list[i]) || |
| is_null_node (expression_list[i]) || |
| !side_effect_list[i] |
| ) |
| { |
| free_node(node_allocator_,expression_list[i]); |
| continue; |
| } |
| else |
| tmp_expression_list.push_back(expression_list[i]); |
| } |
| |
| if (!return_node_present) |
| { |
| tmp_expression_list.push_back(expression_list.back()); |
| } |
| |
| expression_list.swap(tmp_expression_list); |
| |
| if (tmp_expression_list.size() > expression_list.size()) |
| { |
| exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", |
| static_cast<int>(tmp_expression_list.size()), |
| static_cast<int>(expression_list .size()))); |
| } |
| |
| if ( |
| return_node_present || |
| side_effect_list.back() || |
| (expression_list.size() > 1) |
| ) |
| state_.activate_side_effect("simplify()"); |
| |
| if (1 == expression_list.size()) |
| return expression_list[0]; |
| else |
| return expression_generator_.vararg_function(details::e_multi,expression_list); |
| } |
| |
| inline expression_node_ptr parse_multi_sequence(const std::string& source = "") |
| { |
| token_t::token_type close_bracket = token_t::e_rcrlbracket; |
| token_t::token_type seperator = token_t::e_eof; |
| |
| if (!token_is(token_t::e_lcrlbracket)) |
| { |
| if (token_is(token_t::e_lbracket)) |
| { |
| close_bracket = token_t::e_rbracket; |
| seperator = token_t::e_comma; |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR091 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + |
| ((!source.empty()) ? std::string(" section of " + source): ""))); |
| |
| return error_node(); |
| } |
| } |
| else if (token_is(token_t::e_rcrlbracket)) |
| { |
| return node_allocator_.allocate<details::null_node<T> >(); |
| } |
| |
| std::vector<expression_node_ptr> arg_list; |
| std::vector<bool> side_effect_list; |
| |
| expression_node_ptr result = error_node(); |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| scope_handler sh(*this); |
| |
| scoped_bool_or_restorer sbr(state_.side_effect_present); |
| |
| for ( ; ; ) |
| { |
| state_.side_effect_present = false; |
| |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| else |
| { |
| arg_list.push_back(arg); |
| side_effect_list.push_back(state_.side_effect_present); |
| } |
| |
| if (token_is(close_bracket)) |
| break; |
| |
| bool is_next_close = peek_token_is(close_bracket); |
| |
| if (!token_is(seperator) && is_next_close) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR092 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); |
| |
| return error_node(); |
| } |
| |
| if (token_is(close_bracket)) |
| break; |
| } |
| |
| result = simplify(arg_list,side_effect_list); |
| |
| sdd.delete_ptr = (0 == result); |
| return result; |
| } |
| |
| inline bool parse_range(range_t& rp, const bool skip_lsqr = false) |
| { |
| // Examples of valid ranges: |
| // 1. [1:5] -> 1..5 |
| // 2. [ :5] -> 0..5 |
| // 3. [1: ] -> 1..end |
| // 4. [x:y] -> x..y where x <= y |
| // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 |
| // 6. [ :y] -> 0..y where 0 <= y |
| // 7. [x: ] -> x..end where x <= end |
| |
| rp.clear(); |
| |
| if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR093 - Expected '[' for start of range")); |
| |
| return false; |
| } |
| |
| if (token_is(token_t::e_colon)) |
| { |
| rp.n0_c.first = true; |
| rp.n0_c.second = 0; |
| rp.cache.first = 0; |
| } |
| else |
| { |
| expression_node_ptr r0 = parse_expression(); |
| |
| if (0 == r0) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR094 - Failed parse begin section of range")); |
| |
| return false; |
| |
| } |
| else if (is_constant_node(r0)) |
| { |
| T r0_value = r0->value(); |
| |
| if (r0_value >= T(0)) |
| { |
| rp.n0_c.first = true; |
| rp.n0_c.second = static_cast<std::size_t>(details::numeric::to_int64(r0_value)); |
| rp.cache.first = rp.n0_c.second; |
| } |
| |
| free_node(node_allocator_,r0); |
| |
| if (r0_value < T(0)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR095 - Range lower bound less than zero! Constraint: r0 >= 0")); |
| |
| return false; |
| } |
| } |
| else |
| { |
| rp.n0_e.first = true; |
| rp.n0_e.second = r0; |
| } |
| |
| if (!token_is(token_t::e_colon)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR096 - Expected ':' for break in range")); |
| |
| rp.free(); |
| return false; |
| } |
| } |
| |
| if (token_is(token_t::e_rsqrbracket)) |
| { |
| rp.n1_c.first = true; |
| rp.n1_c.second = std::numeric_limits<std::size_t>::max(); |
| } |
| else |
| { |
| expression_node_ptr r1 = parse_expression(); |
| |
| if (0 == r1) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR097 - Failed parse end section of range")); |
| |
| rp.free(); |
| return false; |
| |
| } |
| else if (is_constant_node(r1)) |
| { |
| T r1_value = r1->value(); |
| |
| if (r1_value >= T(0)) |
| { |
| rp.n1_c.first = true; |
| rp.n1_c.second = static_cast<std::size_t>(details::numeric::to_int64(r1_value)); |
| rp.cache.second = rp.n1_c.second; |
| } |
| |
| free_node(node_allocator_,r1); |
| |
| if (r1_value < T(0)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR098 - Range upper bound less than zero! Constraint: r1 >= 0")); |
| |
| return false; |
| } |
| } |
| else |
| { |
| rp.n1_e.first = true; |
| rp.n1_e.second = r1; |
| } |
| |
| if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR099 - Expected ']' for start of range")); |
| |
| rp.free(); |
| return false; |
| } |
| } |
| |
| if (rp.const_range()) |
| { |
| std::size_t r0 = 0; |
| std::size_t r1 = 0; |
| |
| bool rp_result = rp(r0,r1); |
| |
| if (!rp_result || (r0 > r1)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR100 - Invalid range, Constraint: r0 <= r1")); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| inline void lodge_symbol(const std::string& symbol, |
| const symbol_type st) |
| { |
| dec_.add_symbol(symbol,st); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr parse_string() |
| { |
| const std::string symbol = current_token().value; |
| |
| typedef details::stringvar_node<T>* strvar_node_t; |
| |
| expression_node_ptr result = error_node(); |
| strvar_node_t const_str_node = static_cast<strvar_node_t>(0); |
| bool is_const_string = false; |
| |
| scope_element& se = sem_.get_active_element(symbol); |
| |
| if (scope_element::e_string == se.type) |
| { |
| se.active = true; |
| result = se.str_node; |
| lodge_symbol(symbol,e_st_local_string); |
| } |
| else |
| { |
| if (!symtab_store_.is_conststr_stringvar(symbol)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR101 - Unknown string symbol")); |
| |
| return error_node(); |
| } |
| |
| result = symtab_store_.get_stringvar(symbol); |
| |
| is_const_string = symtab_store_.is_constant_string(symbol); |
| |
| if (is_const_string) |
| { |
| const_str_node = static_cast<strvar_node_t>(result); |
| result = expression_generator_(const_str_node->str()); |
| } |
| |
| lodge_symbol(symbol,e_st_string); |
| } |
| |
| if (peek_token_is(token_t::e_lsqrbracket)) |
| { |
| next_token(); |
| |
| if (peek_token_is(token_t::e_rsqrbracket)) |
| { |
| next_token(); |
| next_token(); |
| |
| if (const_str_node) |
| { |
| free_node(node_allocator_,result); |
| |
| return expression_generator_(T(const_str_node->size())); |
| } |
| else |
| return node_allocator_.allocate<details::stringvar_size_node<T> > |
| (static_cast<details::stringvar_node<T>*>(result)->ref()); |
| } |
| |
| range_t rp; |
| |
| if (!parse_range(rp)) |
| { |
| free_node(node_allocator_,result); |
| |
| return error_node(); |
| } |
| else if (const_str_node) |
| { |
| free_node(node_allocator_,result); |
| result = expression_generator_(const_str_node->ref(),rp); |
| } |
| else |
| result = expression_generator_(static_cast<details::stringvar_node<T>*>(result)->ref(),rp); |
| |
| if (result) |
| rp.clear(); |
| } |
| else |
| next_token(); |
| |
| return result; |
| } |
| #else |
| inline expression_node_ptr parse_string() |
| { |
| return error_node(); |
| } |
| #endif |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr parse_const_string() |
| { |
| const std::string const_str = current_token().value; |
| expression_node_ptr result = expression_generator_(const_str); |
| |
| if (peek_token_is(token_t::e_lsqrbracket)) |
| { |
| next_token(); |
| |
| if (peek_token_is(token_t::e_rsqrbracket)) |
| { |
| next_token(); |
| next_token(); |
| |
| free_node(node_allocator_,result); |
| |
| return expression_generator_(T(const_str.size())); |
| } |
| |
| range_t rp; |
| |
| if (!parse_range(rp)) |
| { |
| free_node(node_allocator_,result); |
| |
| return error_node(); |
| } |
| |
| free_node(node_allocator_,result); |
| |
| if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits<std::size_t>::max())) |
| { |
| rp.n1_c.second = const_str.size() - 1; |
| rp.cache.second = rp.n1_c.second; |
| } |
| |
| if ( |
| (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || |
| (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR102 - Overflow in range for string: '" + const_str + "'[" + |
| (rp.n0_c.first ? details::to_str(static_cast<int>(rp.n0_c.second)) : "?") + ":" + |
| (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]")); |
| |
| return error_node(); |
| } |
| |
| result = expression_generator_(const_str,rp); |
| |
| if (result) |
| rp.clear(); |
| } |
| else |
| next_token(); |
| |
| return result; |
| } |
| #else |
| inline expression_node_ptr parse_const_string() |
| { |
| return error_node(); |
| } |
| #endif |
| |
| inline expression_node_ptr parse_vector() |
| { |
| const std::string symbol = current_token().value; |
| |
| vector_holder_ptr vec = vector_holder_ptr(0); |
| |
| const scope_element& se = sem_.get_active_element(symbol); |
| |
| if ( |
| (se.name != symbol) || |
| (se.depth > state_.scope_depth) || |
| (scope_element::e_vector != se.type) |
| ) |
| { |
| if (0 == (vec = symtab_store_.get_vector(symbol))) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR103 - Symbol '" + symbol+ " not a vector")); |
| |
| return error_node(); |
| } |
| } |
| else |
| vec = se.vec_node; |
| |
| expression_node_ptr index_expr = error_node(); |
| |
| next_token(); |
| |
| if (!token_is(token_t::e_lsqrbracket)) |
| { |
| return node_allocator_.allocate<vector_node_t>(vec); |
| } |
| else if (token_is(token_t::e_rsqrbracket)) |
| { |
| return expression_generator_(T(vec->size())); |
| } |
| else if (0 == (index_expr = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR104 - Failed to parse index for vector: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR105 - Expected ']' for index of vector: '" + symbol + "'")); |
| |
| free_node(node_allocator_,index_expr); |
| |
| return error_node(); |
| } |
| |
| return expression_generator_.vector_element(symbol,vec,index_expr); |
| } |
| |
| inline expression_node_ptr parse_vararg_function_call(ivararg_function<T>* vararg_function, const std::string& vararg_function_name) |
| { |
| std::vector<expression_node_ptr> arg_list; |
| expression_node_ptr result = error_node(); |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| next_token(); |
| |
| if (token_is(token_t::e_lbracket)) |
| { |
| if (token_is(token_t::e_rbracket)) |
| { |
| if (!vararg_function->allow_zero_parameters()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR106 - Zero parameter call to vararg function: " |
| + vararg_function_name + " not allowed")); |
| |
| return error_node(); |
| } |
| } |
| else |
| { |
| for ( ; ; ) |
| { |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| else |
| arg_list.push_back(arg); |
| |
| if (token_is(token_t::e_rbracket)) |
| break; |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR107 - Expected ',' for call to vararg function: " |
| + vararg_function_name)); |
| |
| return error_node(); |
| } |
| } |
| } |
| } |
| else if (!vararg_function->allow_zero_parameters()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR108 - Zero parameter call to vararg function: " |
| + vararg_function_name + " not allowed")); |
| |
| return error_node(); |
| } |
| |
| if (arg_list.size() < vararg_function->min_num_args()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR109 - Invalid number of parameters to call to vararg function: " |
| + vararg_function_name + ", require at least " |
| + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters")); |
| |
| return error_node(); |
| } |
| else if (arg_list.size() > vararg_function->max_num_args()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR110 - Invalid number of parameters to call to vararg function: " |
| + vararg_function_name + ", require no more than " |
| + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters")); |
| |
| return error_node(); |
| } |
| |
| result = expression_generator_.vararg_function_call(vararg_function,arg_list); |
| |
| sdd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| class type_checker |
| { |
| public: |
| |
| typedef parser<T> parser_t; |
| typedef std::vector<std::string> param_seq_list_t; |
| |
| type_checker(parser_t& p, |
| const std::string& func_name, |
| const std::string& param_seq) |
| : invalid_state_(true), |
| parser_(p), |
| function_name_(func_name) |
| { |
| split(param_seq); |
| } |
| |
| bool verify(const std::string& param_seq, std::size_t& pseq_index) |
| { |
| if (param_seq_list_.empty()) |
| return true; |
| |
| std::vector<std::pair<std::size_t,char> > error_list; |
| |
| for (std::size_t i = 0; i < param_seq_list_.size(); ++i) |
| { |
| details::char_t diff_value = 0; |
| std::size_t diff_index = 0; |
| |
| bool result = details::sequence_match(param_seq_list_[i], |
| param_seq, |
| diff_index,diff_value); |
| |
| if (result) |
| { |
| pseq_index = i; |
| return true; |
| } |
| else |
| error_list.push_back(std::make_pair(diff_index,diff_value)); |
| } |
| |
| if (1 == error_list.size()) |
| { |
| parser_. |
| set_error( |
| make_error(parser_error::e_syntax, |
| parser_.current_token(), |
| "ERR111 - Failed parameter type check for function '" + function_name_ + "', " |
| "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'")); |
| } |
| else |
| { |
| // find first with largest diff_index; |
| std::size_t max_diff_index = 0; |
| |
| for (std::size_t i = 1; i < error_list.size(); ++i) |
| { |
| if (error_list[i].first > error_list[max_diff_index].first) |
| { |
| max_diff_index = i; |
| } |
| } |
| |
| parser_. |
| set_error( |
| make_error(parser_error::e_syntax, |
| parser_.current_token(), |
| "ERR112 - Failed parameter type check for function '" + function_name_ + "', " |
| "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'")); |
| } |
| |
| return false; |
| } |
| |
| std::size_t paramseq_count() const |
| { |
| return param_seq_list_.size(); |
| } |
| |
| std::string paramseq(const std::size_t& index) const |
| { |
| return param_seq_list_[index]; |
| } |
| |
| bool invalid() const |
| { |
| return !invalid_state_; |
| } |
| |
| bool allow_zero_parameters() const |
| { |
| return |
| param_seq_list_.end() != std::find(param_seq_list_.begin(), |
| param_seq_list_.end(), |
| "Z"); |
| } |
| |
| private: |
| |
| void split(const std::string& s) |
| { |
| if (s.empty()) |
| return; |
| |
| std::size_t start = 0; |
| std::size_t end = 0; |
| |
| param_seq_list_t param_seq_list; |
| |
| struct token_validator |
| { |
| static inline bool process(const std::string& str, |
| std::size_t s, std::size_t e, |
| param_seq_list_t& psl) |
| { |
| if ( |
| (e - s) && |
| (std::string::npos == str.find("?*")) && |
| (std::string::npos == str.find("**")) |
| ) |
| { |
| const std::string curr_str = str.substr(s,e - s); |
| |
| if ("Z" == curr_str) |
| { |
| psl.push_back(curr_str); |
| return true; |
| } |
| else if (std::string::npos == curr_str.find_first_not_of("STV*?|")) |
| { |
| psl.push_back(curr_str); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| }; |
| |
| while (std::string::npos != (end = s.find('|',start))) |
| { |
| if (!token_validator::process(s,start,end,param_seq_list)) |
| { |
| invalid_state_ = false; |
| |
| const std::string err_param_seq = s.substr(start,end - start); |
| |
| parser_. |
| set_error( |
| make_error(parser_error::e_syntax, |
| parser_.current_token(), |
| "ERR113 - Invalid parameter sequence of '" + err_param_seq + |
| "' for function: " + function_name_)); |
| |
| return; |
| } |
| else |
| start = end + 1; |
| } |
| |
| if (start < s.size()) |
| { |
| if (token_validator::process(s,start,s.size(),param_seq_list)) |
| param_seq_list_ = param_seq_list; |
| else |
| { |
| const std::string err_param_seq = s.substr(start,s.size() - start); |
| |
| parser_. |
| set_error( |
| make_error(parser_error::e_syntax, |
| parser_.current_token(), |
| "ERR114 - Invalid parameter sequence of '" + err_param_seq + |
| "' for function: " + function_name_)); |
| return; |
| } |
| } |
| } |
| |
| type_checker(const type_checker&); |
| type_checker& operator=(const type_checker&); |
| |
| bool invalid_state_; |
| parser_t& parser_; |
| std::string function_name_; |
| param_seq_list_t param_seq_list_; |
| }; |
| |
| inline expression_node_ptr parse_generic_function_call(igeneric_function<T>* function, const std::string& function_name) |
| { |
| std::vector<expression_node_ptr> arg_list; |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| next_token(); |
| |
| std::string param_type_list; |
| |
| type_checker tc(*this,function_name,function->parameter_sequence); |
| |
| if (tc.invalid()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR115 - Type checker instantiation failure for generic function: " + function_name)); |
| |
| return error_node(); |
| } |
| |
| if ( |
| !function->parameter_sequence.empty() && |
| function->allow_zero_parameters () && |
| !tc .allow_zero_parameters () |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR116 - Mismatch in zero parameter condition for generic function: " |
| + function_name)); |
| |
| return error_node(); |
| } |
| |
| if (token_is(token_t::e_lbracket)) |
| { |
| if (token_is(token_t::e_rbracket)) |
| { |
| if ( |
| !function->allow_zero_parameters() && |
| !tc .allow_zero_parameters() |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR117 - Zero parameter call to generic function: " |
| + function_name + " not allowed")); |
| |
| return error_node(); |
| } |
| } |
| else |
| { |
| for ( ; ; ) |
| { |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| |
| if (is_ivector_node(arg)) |
| param_type_list += 'V'; |
| else if (is_generally_string_node(arg)) |
| param_type_list += 'S'; |
| else // Everything else is assumed to be a scalar returning expression |
| param_type_list += 'T'; |
| |
| arg_list.push_back(arg); |
| |
| if (token_is(token_t::e_rbracket)) |
| break; |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR118 - Expected ',' for call to generic function: " + function_name)); |
| |
| return error_node(); |
| } |
| } |
| } |
| } |
| else if ( |
| !function->parameter_sequence.empty() && |
| function->allow_zero_parameters () && |
| !tc .allow_zero_parameters () |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR119 - Zero parameter call to generic function: " |
| + function_name + " not allowed")); |
| |
| return error_node(); |
| } |
| |
| std::size_t param_seq_index = 0; |
| |
| if (!tc.verify(param_type_list, param_seq_index)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR120 - Expected ',' for call to generic function: " + function_name)); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr result = error_node(); |
| |
| if (tc.paramseq_count() <= 1) |
| result = expression_generator_ |
| .generic_function_call(function,arg_list); |
| else |
| result = expression_generator_ |
| .generic_function_call(function,arg_list,param_seq_index); |
| |
| sdd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name) |
| { |
| std::vector<expression_node_ptr> arg_list; |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| next_token(); |
| |
| std::string param_type_list; |
| |
| type_checker tc(*this,function_name,function->parameter_sequence); |
| |
| if ( |
| (!function->parameter_sequence.empty()) && |
| (0 == tc.paramseq_count()) |
| ) |
| { |
| return error_node(); |
| } |
| |
| if (token_is(token_t::e_lbracket)) |
| { |
| if (!token_is(token_t::e_rbracket)) |
| { |
| for ( ; ; ) |
| { |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| |
| if (is_ivector_node(arg)) |
| param_type_list += 'V'; |
| else if (is_generally_string_node(arg)) |
| param_type_list += 'S'; |
| else // Everything else is a scalar returning expression |
| param_type_list += 'T'; |
| |
| arg_list.push_back(arg); |
| |
| if (token_is(token_t::e_rbracket)) |
| break; |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR121 - Expected ',' for call to string function: " + function_name)); |
| |
| return error_node(); |
| } |
| } |
| } |
| } |
| |
| std::size_t param_seq_index = 0; |
| |
| if (!tc.verify(param_type_list, param_seq_index)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR122 - Expected ',' for call to string function: " + function_name)); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr result = error_node(); |
| |
| if (tc.paramseq_count() <= 1) |
| result = expression_generator_ |
| .string_function_call(function,arg_list); |
| else |
| result = expression_generator_ |
| .string_function_call(function,arg_list,param_seq_index); |
| |
| sdd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| template <typename Type, std::size_t NumberOfParameters> |
| struct parse_special_function_impl |
| { |
| static inline expression_node_ptr process(parser<Type>& p,const details::operator_type opt_type) |
| { |
| expression_node_ptr branch[NumberOfParameters]; |
| expression_node_ptr result = error_node(); |
| std::fill_n(branch,NumberOfParameters,reinterpret_cast<expression_node_ptr>(0)); |
| scoped_delete<expression_node_t,NumberOfParameters> sd(p,branch); |
| |
| p.next_token(); |
| |
| if (!p.token_is(token_t::e_lbracket)) |
| { |
| p.set_error( |
| make_error(parser_error::e_syntax, |
| p.current_token(), |
| "ERR123 - Expected '(' for special function")); |
| |
| return error_node(); |
| } |
| |
| for (std::size_t i = 0; i < NumberOfParameters; ++i) |
| { |
| branch[i] = p.parse_expression(); |
| |
| if (0 == branch[i]) |
| { |
| return p.error_node(); |
| } |
| else if (i < (NumberOfParameters - 1)) |
| { |
| if (!p.token_is(token_t::e_comma)) |
| { |
| p.set_error( |
| make_error(parser_error::e_syntax, |
| p.current_token(), |
| "ERR124 - Expected ',' before next parameter of special function")); |
| |
| return p.error_node(); |
| } |
| } |
| } |
| |
| if (!p.token_is(token_t::e_rbracket)) |
| return p.error_node(); |
| else |
| result = p.expression_generator_.special_function(opt_type,branch); |
| |
| sd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| }; |
| |
| inline expression_node_ptr parse_special_function() |
| { |
| // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) |
| if ( |
| !details::is_digit(current_token().value[2]) || |
| !details::is_digit(current_token().value[3]) |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_token, |
| current_token(), |
| "ERR125 - Invalid special function[1]: " + current_token().value)); |
| |
| return error_node(); |
| } |
| |
| const unsigned int id = (current_token().value[2] - '0') * 10 + (current_token().value[3] - '0'); |
| |
| if (id >= details::e_sffinal) |
| { |
| set_error( |
| make_error(parser_error::e_token, |
| current_token(), |
| "ERR126 - Invalid special function[2]: " + current_token().value)); |
| |
| return error_node(); |
| } |
| |
| const std::size_t sf_3_to_4 = details::e_sf48; |
| const details::operator_type opt_type = details::operator_type(id + 1000); |
| const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3 : 4; |
| |
| switch (NumberOfParameters) |
| { |
| case 3 : return parse_special_function_impl<T,3>::process(*this,opt_type); |
| case 4 : return parse_special_function_impl<T,4>::process(*this,opt_type); |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr parse_null_statement() |
| { |
| next_token(); |
| return node_allocator_.allocate<details::null_node<T> >(); |
| } |
| |
| #ifndef exprtk_disable_break_continue |
| inline expression_node_ptr parse_break_statement() |
| { |
| if (state_.parsing_break_stmt) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR127 - Break call within a break call is not allowed")); |
| |
| return error_node(); |
| } |
| |
| scoped_bool_negator sbn(state_.parsing_break_stmt); |
| |
| if (!brkcnt_list_.empty()) |
| { |
| next_token(); |
| |
| brkcnt_list_.front() = true; |
| |
| expression_node_ptr return_expr = error_node(); |
| |
| if (token_is(token_t::e_lsqrbracket)) |
| { |
| if (0 == (return_expr = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR128 - Failed to parse return expression for 'break' statement")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR129 - Expected ']' at the completion of break's return expression")); |
| |
| free_node(node_allocator_,return_expr); |
| |
| return error_node(); |
| } |
| } |
| |
| state_.activate_side_effect("parse_break_statement()"); |
| |
| return node_allocator_.allocate<details::break_node<T> >(return_expr); |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR130 - Invalid use of 'break', allowed only in the scope of a loop")); |
| } |
| |
| return error_node(); |
| } |
| |
| inline expression_node_ptr parse_continue_statement() |
| { |
| if (!brkcnt_list_.empty()) |
| { |
| next_token(); |
| |
| brkcnt_list_.front() = true; |
| state_.activate_side_effect("parse_continue_statement()"); |
| |
| return node_allocator_.allocate<details::continue_node<T> >(); |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR131 - Invalid use of 'continue', allowed only in the scope of a loop")); |
| |
| return error_node(); |
| } |
| } |
| #endif |
| |
| inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) |
| { |
| expression_node_ptr size_expr = error_node(); |
| |
| if (!token_is(token_t::e_lsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR132 - Expected '[' as part of vector size definition")); |
| |
| return error_node(); |
| } |
| else if (0 == (size_expr = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR133 - Failed to determine size of vector '" + vec_name + "'")); |
| |
| return error_node(); |
| } |
| else if (!is_constant_node(size_expr)) |
| { |
| free_node(node_allocator_,size_expr); |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR134 - Expected a literal number as size of vector '" + vec_name + "'")); |
| |
| return error_node(); |
| } |
| |
| T vector_size = size_expr->value(); |
| |
| free_node(node_allocator_,size_expr); |
| |
| if ( |
| (vector_size <= T(0)) || |
| std::not_equal_to<T>() |
| (T(0),vector_size - details::numeric::trunc(vector_size)) |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR135 - Invalid vector size. Must be an integer greater than zero, size: " + |
| details::to_str(details::numeric::to_int32(vector_size)))); |
| |
| return error_node(); |
| } |
| |
| std::vector<expression_node_ptr> vec_initilizer_list; |
| |
| scoped_vec_delete<expression_node_t> svd(*this,vec_initilizer_list); |
| |
| bool single_value_initialiser = false; |
| bool vec_to_vec_initialiser = false; |
| bool null_initialisation = false; |
| |
| if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR136 - Expected ']' as part of vector size definition")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_eof)) |
| { |
| if (!token_is(token_t::e_assign)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR137 - Expected ':=' as part of vector definition")); |
| |
| return error_node(); |
| } |
| else if (token_is(token_t::e_lsqrbracket)) |
| { |
| expression_node_ptr initialiser = parse_expression(); |
| |
| if (0 == initialiser) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR138 - Failed to parse single vector initialiser")); |
| |
| return error_node(); |
| } |
| |
| vec_initilizer_list.push_back(initialiser); |
| |
| if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR139 - Expected ']' to close single value vector initialiser")); |
| |
| return error_node(); |
| } |
| |
| single_value_initialiser = true; |
| } |
| else if (!token_is(token_t::e_lcrlbracket)) |
| { |
| expression_node_ptr initialiser = error_node(); |
| |
| // Is this a vector to vector assignment and initialisation? |
| if (token_t::e_symbol == current_token().type) |
| { |
| // Is it a locally defined vector? |
| scope_element& se = sem_.get_active_element(current_token().value); |
| |
| if (scope_element::e_vector == se.type) |
| { |
| if (0 != (initialiser = parse_expression())) |
| vec_initilizer_list.push_back(initialiser); |
| else |
| return error_node(); |
| } |
| // Are we dealing with a user defined vector? |
| else if (symtab_store_.is_vector(current_token().value)) |
| { |
| lodge_symbol(current_token().value,e_st_vector); |
| |
| if (0 != (initialiser = parse_expression())) |
| vec_initilizer_list.push_back(initialiser); |
| else |
| return error_node(); |
| } |
| // Are we dealing with a null initialisation vector definition? |
| else if (token_is(token_t::e_symbol,"null")) |
| null_initialisation = true; |
| } |
| |
| if (!null_initialisation) |
| { |
| if (0 == initialiser) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR140 - Expected '{' as part of vector initialiser list")); |
| |
| return error_node(); |
| } |
| else |
| vec_to_vec_initialiser = true; |
| } |
| } |
| else if (!token_is(token_t::e_rcrlbracket)) |
| { |
| for ( ; ; ) |
| { |
| expression_node_ptr initialiser = parse_expression(); |
| |
| if (0 == initialiser) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR141 - Expected '{' as part of vector initialiser list")); |
| |
| return error_node(); |
| } |
| else |
| vec_initilizer_list.push_back(initialiser); |
| |
| if (token_is(token_t::e_rcrlbracket)) |
| break; |
| |
| bool is_next_close = peek_token_is(token_t::e_rcrlbracket); |
| |
| if (!token_is(token_t::e_comma) && is_next_close) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR142 - Expected ',' between vector initialisers")); |
| |
| return error_node(); |
| } |
| |
| if (token_is(token_t::e_rcrlbracket)) |
| break; |
| } |
| } |
| |
| if ( |
| !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && |
| !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && |
| !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) |
| ) |
| { |
| if (!token_is(token_t::e_eof)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR143 - Expected ';' at end of vector definition")); |
| |
| return error_node(); |
| } |
| } |
| |
| if (vec_initilizer_list.size() > vector_size) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR144 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); |
| |
| return error_node(); |
| } |
| } |
| |
| typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); |
| |
| std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size)); |
| |
| scope_element& se = sem_.get_element(vec_name); |
| |
| if (se.name == vec_name) |
| { |
| if (se.active) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR145 - Illegal redefinition of local vector: '" + vec_name + "'")); |
| |
| return error_node(); |
| } |
| else if ( |
| (se.size == vec_size) && |
| (scope_element::e_vector == se.type) |
| ) |
| { |
| vec_holder = se.vec_node; |
| se.active = true; |
| se.depth = state_.scope_depth; |
| se.ref_count++; |
| } |
| } |
| |
| if (0 == vec_holder) |
| { |
| scope_element nse; |
| nse.name = vec_name; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_vector; |
| nse.depth = state_.scope_depth; |
| nse.size = vec_size; |
| nse.data = new T[vec_size]; |
| nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); |
| |
| if (!sem_.add_element(nse)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR146 - Failed to add new local vector '" + vec_name + "' to SEM")); |
| |
| sem_.free_element(nse); |
| |
| return error_node(); |
| } |
| |
| vec_holder = nse.vec_node; |
| |
| exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", |
| nse.name.c_str(), |
| static_cast<int>(nse.size))); |
| } |
| |
| state_.activate_side_effect("parse_define_vector_statement()"); |
| |
| lodge_symbol(vec_name,e_st_local_vector); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (null_initialisation) |
| result = expression_generator_(T(0.0)); |
| else if (vec_to_vec_initialiser) |
| result = expression_generator_( |
| details::e_assign, |
| node_allocator_.allocate<vector_node_t>(vec_holder), |
| vec_initilizer_list[0]); |
| else |
| result = node_allocator_ |
| .allocate<details::vector_assignment_node<T> >( |
| (*vec_holder)[0], |
| vec_size, |
| vec_initilizer_list, |
| single_value_initialiser); |
| |
| svd.delete_ptr = (0 == result); |
| |
| return result; |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) |
| { |
| stringvar_node_t* str_node = reinterpret_cast<stringvar_node_t*>(0); |
| |
| scope_element& se = sem_.get_element(str_name); |
| |
| if (se.name == str_name) |
| { |
| if (se.active) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR147 - Illegal redefinition of local variable: '" + str_name + "'")); |
| |
| free_node(node_allocator_,initialisation_expression); |
| |
| return error_node(); |
| } |
| else if (scope_element::e_string == se.type) |
| { |
| str_node = se.str_node; |
| se.active = true; |
| se.depth = state_.scope_depth; |
| se.ref_count++; |
| } |
| } |
| |
| if (0 == str_node) |
| { |
| scope_element nse; |
| nse.name = str_name; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_string; |
| nse.depth = state_.scope_depth; |
| nse.data = new std::string; |
| nse.str_node = new stringvar_node_t(*(std::string*)(nse.data)); |
| |
| if (!sem_.add_element(nse)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR148 - Failed to add new local string variable '" + str_name + "' to SEM")); |
| |
| free_node(node_allocator_,initialisation_expression); |
| |
| sem_.free_element(nse); |
| |
| return error_node(); |
| } |
| |
| str_node = nse.str_node; |
| |
| exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); |
| } |
| |
| lodge_symbol(str_name,e_st_local_string); |
| |
| state_.activate_side_effect("parse_define_string_statement()"); |
| |
| expression_node_ptr branch[2] = {0}; |
| |
| branch[0] = str_node; |
| branch[1] = initialisation_expression; |
| |
| return expression_generator_(details::e_assign,branch); |
| } |
| #else |
| inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) |
| { |
| return error_node(); |
| } |
| #endif |
| |
| inline bool local_variable_is_shadowed(const std::string& symbol) |
| { |
| const scope_element& se = sem_.get_element(symbol); |
| return (se.name == symbol) && se.active; |
| } |
| |
| inline expression_node_ptr parse_define_var_statement() |
| { |
| if (settings_.vardef_disabled()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR149 - Illegal variable definition")); |
| |
| return error_node(); |
| } |
| else if (!details::imatch(current_token().value,"var")) |
| { |
| return error_node(); |
| } |
| else |
| next_token(); |
| |
| const std::string var_name = current_token().value; |
| |
| expression_node_ptr initialisation_expression = error_node(); |
| |
| if (!token_is(token_t::e_symbol)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR150 - Expected a symbol for variable definition")); |
| |
| return error_node(); |
| } |
| else if (details::is_reserved_symbol(var_name)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR151 - Illegal redefinition of reserved keyword: '" + var_name + "'")); |
| |
| return error_node(); |
| } |
| else if (symtab_store_.symbol_exists(var_name)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR152 - Illegal redefinition of variable '" + var_name + "'")); |
| |
| return error_node(); |
| } |
| else if (local_variable_is_shadowed(var_name)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR153 - Illegal redefinition of local variable: '" + var_name + "'")); |
| |
| return error_node(); |
| } |
| else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) |
| { |
| return parse_define_vector_statement(var_name); |
| } |
| else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) |
| { |
| return parse_uninitialised_var_statement(var_name); |
| } |
| else if (token_is(token_t::e_assign)) |
| { |
| if (0 == (initialisation_expression = parse_expression())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR154 - Failed to parse initialisation expression")); |
| |
| return error_node(); |
| } |
| } |
| |
| if ( |
| !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && |
| !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && |
| !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) |
| ) |
| { |
| if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR155 - Expected ';' after variable definition")); |
| |
| free_node(node_allocator_,initialisation_expression); |
| |
| return error_node(); |
| } |
| } |
| |
| if ( |
| (0 != initialisation_expression) && |
| details::is_generally_string_node(initialisation_expression) |
| ) |
| { |
| return parse_define_string_statement(var_name,initialisation_expression); |
| } |
| |
| expression_node_ptr var_node = reinterpret_cast<expression_node_ptr>(0); |
| |
| scope_element& se = sem_.get_element(var_name); |
| |
| if (se.name == var_name) |
| { |
| if (se.active) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR156 - Illegal redefinition of local variable: '" + var_name + "'")); |
| |
| free_node(node_allocator_,initialisation_expression); |
| |
| return error_node(); |
| } |
| else if (scope_element::e_variable == se.type) |
| { |
| var_node = se.var_node; |
| se.active = true; |
| se.depth = state_.scope_depth; |
| se.ref_count++; |
| } |
| } |
| |
| if (0 == var_node) |
| { |
| scope_element nse; |
| nse.name = var_name; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_variable; |
| nse.depth = state_.scope_depth; |
| nse.data = new T(T(0)); |
| nse.var_node = node_allocator_.allocate<variable_node_t>(*(T*)(nse.data)); |
| |
| if (!sem_.add_element(nse)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR157 - Failed to add new local variable '" + var_name + "' to SEM")); |
| |
| free_node(node_allocator_,initialisation_expression); |
| |
| sem_.free_element(nse); |
| |
| return error_node(); |
| } |
| |
| var_node = nse.var_node; |
| |
| exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); |
| } |
| |
| state_.activate_side_effect("parse_define_var_statement()"); |
| |
| lodge_symbol(var_name,e_st_local_variable); |
| |
| expression_node_ptr branch[2] = {0}; |
| |
| branch[0] = var_node; |
| branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); |
| |
| return expression_generator_(details::e_assign,branch); |
| } |
| |
| inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) |
| { |
| if ( |
| !token_is(token_t::e_lcrlbracket) || |
| !token_is(token_t::e_rcrlbracket) |
| ) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR158 - Expected a '{}' for uninitialised var definition")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR159 - Expected ';' after uninitialised variable definition")); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr var_node = reinterpret_cast<expression_node_ptr>(0); |
| |
| scope_element& se = sem_.get_element(var_name); |
| |
| if (se.name == var_name) |
| { |
| if (se.active) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR160 - Illegal redefinition of local variable: '" + var_name + "'")); |
| |
| return error_node(); |
| } |
| else if (scope_element::e_variable == se.type) |
| { |
| var_node = se.var_node; |
| se.active = true; |
| se.ref_count++; |
| } |
| } |
| |
| if (0 == var_node) |
| { |
| scope_element nse; |
| nse.name = var_name; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_variable; |
| nse.depth = state_.scope_depth; |
| nse.ip_index = sem_.next_ip_index(); |
| nse.data = new T(T(0)); |
| nse.var_node = node_allocator_.allocate<variable_node_t>(*(T*)(nse.data)); |
| |
| if (!sem_.add_element(nse)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR161 - Failed to add new local variable '" + var_name + "' to SEM")); |
| |
| sem_.free_element(nse); |
| |
| return error_node(); |
| } |
| |
| exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", |
| nse.name.c_str())); |
| } |
| |
| lodge_symbol(var_name,e_st_local_variable); |
| |
| state_.activate_side_effect("parse_uninitialised_var_statement()"); |
| |
| return expression_generator_(T(0)); |
| } |
| |
| inline expression_node_ptr parse_swap_statement() |
| { |
| if (!details::imatch(current_token().value,"swap")) |
| { |
| return error_node(); |
| } |
| else |
| next_token(); |
| |
| if (!token_is(token_t::e_lbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR162 - Expected '(' at start of swap statement")); |
| |
| return error_node(); |
| } |
| |
| expression_node_ptr variable0 = error_node(); |
| expression_node_ptr variable1 = error_node(); |
| |
| bool variable0_generated = false; |
| bool variable1_generated = false; |
| |
| const std::string var0_name = current_token().value; |
| |
| if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR163 - Expected a symbol for variable or vector element definition")); |
| |
| return error_node(); |
| } |
| else if (peek_token_is(token_t::e_lsqrbracket)) |
| { |
| if (0 == (variable0 = parse_vector())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR164 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); |
| |
| return error_node(); |
| } |
| |
| variable0_generated = true; |
| } |
| else |
| { |
| if (symtab_store_.is_variable(var0_name)) |
| { |
| variable0 = symtab_store_.get_variable(var0_name); |
| } |
| |
| scope_element& se = sem_.get_element(var0_name); |
| |
| if ( |
| (se.active) && |
| (se.name == var0_name) && |
| (scope_element::e_variable == se.type) |
| ) |
| { |
| variable0 = se.var_node; |
| } |
| |
| lodge_symbol(var0_name,e_st_variable); |
| |
| if (0 == variable0) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR165 - First parameter to swap is an invalid variable: '" + var0_name + "'")); |
| |
| return error_node(); |
| } |
| else |
| next_token(); |
| } |
| |
| if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR166 - Expected ',' between parameters to swap")); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| return error_node(); |
| } |
| |
| const std::string var1_name = current_token().value; |
| |
| if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR167 - Expected a symbol for variable or vector element definition")); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| return error_node(); |
| } |
| else if (peek_token_is(token_t::e_lsqrbracket)) |
| { |
| if (0 == (variable1 = parse_vector())) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR168 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| return error_node(); |
| } |
| |
| variable1_generated = true; |
| } |
| else |
| { |
| if (symtab_store_.is_variable(var1_name)) |
| { |
| variable1 = symtab_store_.get_variable(var1_name); |
| } |
| |
| scope_element& se = sem_.get_element(var1_name); |
| |
| if ( |
| (se.active) && |
| (se.name == var1_name) && |
| (scope_element::e_variable == se.type) |
| ) |
| { |
| variable1 = se.var_node; |
| } |
| |
| lodge_symbol(var1_name,e_st_variable); |
| |
| if (0 == variable1) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR169 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| return error_node(); |
| } |
| else |
| next_token(); |
| } |
| |
| if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR170 - Expected ')' at end of swap statement")); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| if (variable1_generated) |
| { |
| free_node(node_allocator_,variable1); |
| } |
| |
| return error_node(); |
| } |
| |
| typedef details::variable_node<T>* variable_node_ptr; |
| variable_node_ptr v0 = variable_node_ptr(0); |
| variable_node_ptr v1 = variable_node_ptr(0); |
| |
| expression_node_ptr result = error_node(); |
| |
| if ( |
| (0 != (v0 = dynamic_cast<variable_node_ptr>(variable0))) && |
| (0 != (v1 = dynamic_cast<variable_node_ptr>(variable1))) |
| ) |
| { |
| result = node_allocator_.allocate<details::swap_node<T> >(v0,v1); |
| |
| if (variable0_generated) |
| { |
| free_node(node_allocator_,variable0); |
| } |
| |
| if (variable1_generated) |
| { |
| free_node(node_allocator_,variable1); |
| } |
| } |
| else |
| result = node_allocator_.allocate<details::swap_generic_node<T> >(variable0,variable1); |
| |
| state_.activate_side_effect("parse_swap_statement()"); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr parse_return_statement() |
| { |
| if (state_.parsing_return_stmt) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR171 - Return call within a return call is not allowed")); |
| |
| return error_node(); |
| } |
| |
| scoped_bool_negator sbn(state_.parsing_return_stmt); |
| |
| std::vector<expression_node_ptr> arg_list; |
| |
| scoped_vec_delete<expression_node_t> sdd(*this,arg_list); |
| |
| if (!details::imatch(current_token().value,"return")) |
| { |
| return error_node(); |
| } |
| else |
| next_token(); |
| |
| if (!token_is(token_t::e_lsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR172 - Expected '[' at start of return statement")); |
| |
| return error_node(); |
| } |
| else if (!token_is(token_t::e_rsqrbracket)) |
| { |
| for ( ; ; ) |
| { |
| expression_node_ptr arg = parse_expression(); |
| |
| if (0 == arg) |
| return error_node(); |
| |
| arg_list.push_back(arg); |
| |
| if (token_is(token_t::e_rsqrbracket)) |
| break; |
| else if (!token_is(token_t::e_comma)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR173 - Expected ',' between values during call to return")); |
| |
| return error_node(); |
| } |
| } |
| } |
| else if (settings_.zero_return_disabled()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR174 - Zero parameter return statement not allowed")); |
| |
| return error_node(); |
| } |
| |
| lexer::token prev_token = current_token(); |
| |
| if (token_is(token_t::e_rsqrbracket)) |
| { |
| if (!arg_list.empty()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| prev_token, |
| "ERR175 - Invalid ']' found during return call")); |
| |
| return error_node(); |
| } |
| } |
| |
| std::string ret_param_type_list; |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| if (0 == arg_list[i]) |
| return error_node(); |
| else if (is_ivector_node(arg_list[i])) |
| ret_param_type_list += 'V'; |
| else if (is_generally_string_node(arg_list[i])) |
| ret_param_type_list += 'S'; |
| else |
| ret_param_type_list += 'T'; |
| } |
| |
| dec_.retparam_list_.push_back(ret_param_type_list); |
| |
| expression_node_ptr result = expression_generator_.return_call(arg_list); |
| |
| sdd.delete_ptr = (0 == result); |
| |
| state_.return_stmt_present = true; |
| |
| state_.activate_side_effect("parse_return_statement()"); |
| |
| return result; |
| } |
| |
| inline bool post_variable_process(const std::string& symbol) |
| { |
| if ( |
| peek_token_is(token_t::e_lbracket ) || |
| peek_token_is(token_t::e_lcrlbracket) || |
| peek_token_is(token_t::e_lsqrbracket) |
| ) |
| { |
| if (!settings_.commutative_check_enabled()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR176 - Invalid sequence of variable '"+ symbol + "' and bracket")); |
| |
| return false; |
| } |
| |
| lexer().insert_front(token_t::e_mul); |
| } |
| |
| return true; |
| } |
| |
| inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) |
| { |
| bool implied_mul = false; |
| |
| if (is_generally_string_node(branch)) |
| return true; |
| |
| const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; |
| |
| switch (token) |
| { |
| case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || |
| token_is(token_t::e_lcrlbracket,hold) || |
| token_is(token_t::e_lsqrbracket,hold) ; |
| break; |
| |
| case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || |
| token_is(token_t::e_lcrlbracket,hold) || |
| token_is(token_t::e_lsqrbracket,hold) ; |
| break; |
| |
| case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || |
| token_is(token_t::e_lcrlbracket,hold) || |
| token_is(token_t::e_lsqrbracket,hold) ; |
| break; |
| |
| default : return true; |
| } |
| |
| if (implied_mul) |
| { |
| if (!settings_.commutative_check_enabled()) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR177 - Invalid sequence of brackets")); |
| |
| return false; |
| } |
| else if (token_t::e_eof != current_token().type) |
| { |
| lexer().insert_front(current_token().type); |
| lexer().insert_front(token_t::e_mul); |
| next_token(); |
| } |
| } |
| |
| return true; |
| } |
| |
| inline expression_node_ptr parse_symtab_symbol() |
| { |
| const std::string symbol = current_token().value; |
| |
| // Are we dealing with a variable or a special constant? |
| expression_node_ptr variable = symtab_store_.get_variable(symbol); |
| |
| if (variable) |
| { |
| if (symtab_store_.is_constant_node(symbol)) |
| { |
| variable = expression_generator_(variable->value()); |
| } |
| |
| if (!post_variable_process(symbol)) |
| return error_node(); |
| |
| lodge_symbol(symbol,e_st_variable); |
| next_token(); |
| |
| return variable; |
| } |
| |
| // Are we dealing with a locally defined variable, vector or string? |
| if (!sem_.empty()) |
| { |
| scope_element& se = sem_.get_active_element(symbol); |
| |
| if (se.active && (se.name == symbol)) |
| { |
| if (scope_element::e_variable == se.type) |
| { |
| se.active = true; |
| lodge_symbol(symbol,e_st_local_variable); |
| |
| if (!post_variable_process(symbol)) |
| return error_node(); |
| |
| next_token(); |
| |
| return se.var_node; |
| } |
| else if (scope_element::e_vector == se.type) |
| { |
| return parse_vector(); |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if (scope_element::e_string == se.type) |
| { |
| return parse_string(); |
| } |
| #endif |
| } |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| // Are we dealing with a string variable? |
| if (symtab_store_.is_stringvar(symbol)) |
| { |
| return parse_string(); |
| } |
| #endif |
| |
| { |
| // Are we dealing with a function? |
| ifunction<T>* function = symtab_store_.get_function(symbol); |
| |
| if (function) |
| { |
| lodge_symbol(symbol,e_st_function); |
| |
| expression_node_ptr func_node = |
| parse_function_invocation(function,symbol); |
| |
| if (func_node) |
| return func_node; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR178 - Failed to generate node for function: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| { |
| // Are we dealing with a vararg function? |
| ivararg_function<T>* vararg_function = symtab_store_.get_vararg_function(symbol); |
| |
| if (vararg_function) |
| { |
| lodge_symbol(symbol,e_st_function); |
| |
| expression_node_ptr vararg_func_node = |
| parse_vararg_function_call(vararg_function,symbol); |
| |
| if (vararg_func_node) |
| return vararg_func_node; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR179 - Failed to generate node for vararg function: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| { |
| // Are we dealing with a vararg generic function? |
| igeneric_function<T>* generic_function = symtab_store_.get_generic_function(symbol); |
| |
| if (generic_function) |
| { |
| lodge_symbol(symbol,e_st_function); |
| |
| expression_node_ptr genericfunc_node = |
| parse_generic_function_call(generic_function,symbol); |
| |
| if (genericfunc_node) |
| return genericfunc_node; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR180 - Failed to generate node for generic function: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| { |
| // Are we dealing with a vararg string returning function? |
| igeneric_function<T>* string_function = symtab_store_.get_string_function(symbol); |
| |
| if (string_function) |
| { |
| lodge_symbol(symbol,e_st_function); |
| |
| expression_node_ptr stringfunc_node = |
| parse_string_function_call(string_function,symbol); |
| |
| if (stringfunc_node) |
| return stringfunc_node; |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR181 - Failed to generate node for string function: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| // Are we dealing with a vector? |
| if (symtab_store_.is_vector(symbol)) |
| { |
| lodge_symbol(symbol,e_st_vector); |
| return parse_vector(); |
| } |
| |
| if (details::is_reserved_symbol(symbol)) |
| { |
| if (settings_.function_enabled(symbol) || !details::is_base_function(symbol)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR182 - Invalid use of reserved symbol '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| |
| // Should we handle unknown symbols? |
| if (resolve_unknown_symbol_ && unknown_symbol_resolver_) |
| { |
| if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) |
| { |
| T default_value = T(0); |
| std::string error_message; |
| typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; |
| |
| if (unknown_symbol_resolver_->process(symbol,usr_symbol_type,default_value,error_message)) |
| { |
| bool create_result = false; |
| |
| symbol_table_t& symtab = symtab_store_.get_symbol_table(); |
| |
| switch (usr_symbol_type) |
| { |
| case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol,default_value); |
| break; |
| |
| case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol,default_value); |
| break; |
| |
| default : create_result = false; |
| } |
| |
| if (create_result) |
| { |
| expression_node_ptr var = symtab_store_.get_variable(symbol); |
| |
| if (var) |
| { |
| if (symtab_store_.is_constant_node(symbol)) |
| { |
| var = expression_generator_(var->value()); |
| } |
| |
| lodge_symbol(symbol,e_st_variable); |
| |
| if (!post_variable_process(symbol)) |
| return error_node(); |
| |
| next_token(); |
| |
| return var; |
| } |
| } |
| |
| set_error( |
| make_error(parser_error::e_symtab, |
| current_token(), |
| "ERR183 - Failed to create variable: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR184 - Undefined symbol: '" + symbol + "'")); |
| |
| return error_node(); |
| } |
| |
| inline expression_node_ptr parse_symbol() |
| { |
| static const std::string symbol_if = "if" ; |
| static const std::string symbol_while = "while" ; |
| static const std::string symbol_repeat = "repeat" ; |
| static const std::string symbol_for = "for" ; |
| static const std::string symbol_switch = "switch" ; |
| static const std::string symbol_null = "null" ; |
| static const std::string symbol_break = "break" ; |
| static const std::string symbol_continue = "continue"; |
| static const std::string symbol_var = "var" ; |
| static const std::string symbol_swap = "swap" ; |
| static const std::string symbol_return = "return" ; |
| |
| if (valid_vararg_operation(current_token().value)) |
| { |
| return parse_vararg_function(); |
| } |
| else if (valid_base_operation(current_token().value)) |
| { |
| return parse_base_operation(); |
| } |
| else if ( |
| details::imatch(current_token().value,symbol_if) && |
| settings_.control_struct_enabled(current_token().value) |
| ) |
| { |
| return parse_conditional_statement(); |
| } |
| else if ( |
| details::imatch(current_token().value,symbol_while) && |
| settings_.control_struct_enabled(current_token().value) |
| ) |
| { |
| return parse_while_loop(); |
| } |
| else if ( |
| details::imatch(current_token().value,symbol_repeat) && |
| settings_.control_struct_enabled(current_token().value) |
| ) |
| { |
| return parse_repeat_until_loop(); |
| } |
| else if ( |
| details::imatch(current_token().value,symbol_for) && |
| settings_.control_struct_enabled(current_token().value) |
| ) |
| { |
| return parse_for_loop(); |
| } |
| else if ( |
| details::imatch(current_token().value,symbol_switch) && |
| settings_.control_struct_enabled(current_token().value) |
| ) |
| { |
| return parse_switch_statement(); |
| } |
| else if (details::is_valid_sf_symbol(current_token().value)) |
| { |
| return parse_special_function(); |
| } |
| else if (details::imatch(current_token().value,symbol_null)) |
| { |
| return parse_null_statement(); |
| } |
| #ifndef exprtk_disable_break_continue |
| else if (details::imatch(current_token().value,symbol_break)) |
| { |
| return parse_break_statement(); |
| } |
| else if (details::imatch(current_token().value,symbol_continue)) |
| { |
| return parse_continue_statement(); |
| } |
| #endif |
| else if (details::imatch(current_token().value,symbol_var)) |
| { |
| return parse_define_var_statement(); |
| } |
| else if (details::imatch(current_token().value,symbol_swap)) |
| { |
| return parse_swap_statement(); |
| } |
| else if (details::imatch(current_token().value,symbol_return)) |
| { |
| return parse_return_statement(); |
| } |
| else if (symtab_store_.valid() || !sem_.empty()) |
| { |
| return parse_symtab_symbol(); |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_symtab, |
| current_token(), |
| "ERR185 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); |
| |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) |
| { |
| expression_node_ptr branch = error_node(); |
| |
| if (token_t::e_number == current_token().type) |
| { |
| T numeric_value = T(0); |
| |
| if (details::string_to_real(current_token().value,numeric_value)) |
| { |
| expression_node_ptr literal_exp = expression_generator_(numeric_value); |
| next_token(); |
| branch = literal_exp; |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_numeric, |
| current_token(), |
| "ERR186 - Failed to convert '" + current_token().value + "' to a number")); |
| |
| return error_node(); |
| } |
| } |
| else if (token_t::e_symbol == current_token().type) |
| { |
| branch = parse_symbol(); |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if (token_t::e_string == current_token().type) |
| { |
| branch = parse_const_string(); |
| } |
| #endif |
| else if (token_t::e_lbracket == current_token().type) |
| { |
| next_token(); |
| |
| if (0 == (branch = parse_expression())) |
| return error_node(); |
| else if (!token_is(token_t::e_rbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR187 - Expected ')' instead of: '" + current_token().value + "'")); |
| |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (!post_bracket_process(token_t::e_lbracket,branch)) |
| { |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| } |
| else if (token_t::e_lsqrbracket == current_token().type) |
| { |
| next_token(); |
| |
| if (0 == (branch = parse_expression())) |
| return error_node(); |
| else if (!token_is(token_t::e_rsqrbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR188 - Expected ']' instead of: '" + current_token().value + "'")); |
| |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) |
| { |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| } |
| else if (token_t::e_lcrlbracket == current_token().type) |
| { |
| next_token(); |
| |
| if (0 == (branch = parse_expression())) |
| return error_node(); |
| else if (!token_is(token_t::e_rcrlbracket)) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR189 - Expected '}' instead of: '" + current_token().value + "'")); |
| |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) |
| { |
| free_node(node_allocator_,branch); |
| |
| return error_node(); |
| } |
| } |
| else if (token_t::e_sub == current_token().type) |
| { |
| next_token(); |
| branch = parse_expression(e_level11); |
| |
| if ( |
| branch && |
| !( |
| details::is_neg_unary_node (branch) && |
| simplify_unary_negation_branch(branch) |
| ) |
| ) |
| { |
| branch = expression_generator_(details::e_neg,branch); |
| } |
| } |
| else if (token_t::e_add == current_token().type) |
| { |
| next_token(); |
| branch = parse_expression(e_level13); |
| } |
| else if (token_t::e_eof == current_token().type) |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR190 - Premature end of expression[1]")); |
| |
| return error_node(); |
| } |
| else |
| { |
| set_error( |
| make_error(parser_error::e_syntax, |
| current_token(), |
| "ERR191 - Premature end of expression[2]")); |
| |
| return error_node(); |
| } |
| |
| if ( |
| branch && |
| (e_level00 == precedence) && |
| token_is(token_t::e_ternary,prsrhlpr_t::e_hold) |
| ) |
| { |
| branch = parse_ternary_conditional_statement(branch); |
| } |
| |
| parse_pending_string_rangesize(branch); |
| |
| return branch; |
| } |
| |
| template <typename Type> |
| class expression_generator |
| { |
| public: |
| |
| typedef details::expression_node<Type>* expression_node_ptr; |
| typedef expression_node_ptr (*synthesize_functor_t)(expression_generator<T>&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); |
| typedef std::map<std::string,synthesize_functor_t> synthesize_map_t; |
| typedef typename exprtk::parser<Type> parser_t; |
| typedef const Type& vtype; |
| typedef const Type ctype; |
| |
| inline void init_synthesize_map() |
| { |
| #ifndef exprtk_disable_enhanced_features |
| synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; |
| synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; |
| synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; |
| |
| #define register_synthezier(S) \ |
| synthesize_map_[S ::node_type::id()] = S ::process; \ |
| |
| register_synthezier(synthesize_vovov_expression0) |
| register_synthezier(synthesize_vovov_expression1) |
| register_synthezier(synthesize_vovoc_expression0) |
| register_synthezier(synthesize_vovoc_expression1) |
| register_synthezier(synthesize_vocov_expression0) |
| register_synthezier(synthesize_vocov_expression1) |
| register_synthezier(synthesize_covov_expression0) |
| register_synthezier(synthesize_covov_expression1) |
| register_synthezier(synthesize_covoc_expression0) |
| register_synthezier(synthesize_covoc_expression1) |
| register_synthezier(synthesize_cocov_expression1) |
| register_synthezier(synthesize_vococ_expression0) |
| |
| register_synthezier(synthesize_vovovov_expression0) |
| register_synthezier(synthesize_vovovoc_expression0) |
| register_synthezier(synthesize_vovocov_expression0) |
| register_synthezier(synthesize_vocovov_expression0) |
| register_synthezier(synthesize_covovov_expression0) |
| register_synthezier(synthesize_covocov_expression0) |
| register_synthezier(synthesize_vocovoc_expression0) |
| register_synthezier(synthesize_covovoc_expression0) |
| register_synthezier(synthesize_vococov_expression0) |
| |
| register_synthezier(synthesize_vovovov_expression1) |
| register_synthezier(synthesize_vovovoc_expression1) |
| register_synthezier(synthesize_vovocov_expression1) |
| register_synthezier(synthesize_vocovov_expression1) |
| register_synthezier(synthesize_covovov_expression1) |
| register_synthezier(synthesize_covocov_expression1) |
| register_synthezier(synthesize_vocovoc_expression1) |
| register_synthezier(synthesize_covovoc_expression1) |
| register_synthezier(synthesize_vococov_expression1) |
| |
| register_synthezier(synthesize_vovovov_expression2) |
| register_synthezier(synthesize_vovovoc_expression2) |
| register_synthezier(synthesize_vovocov_expression2) |
| register_synthezier(synthesize_vocovov_expression2) |
| register_synthezier(synthesize_covovov_expression2) |
| register_synthezier(synthesize_covocov_expression2) |
| register_synthezier(synthesize_vocovoc_expression2) |
| register_synthezier(synthesize_covovoc_expression2) |
| |
| register_synthezier(synthesize_vovovov_expression3) |
| register_synthezier(synthesize_vovovoc_expression3) |
| register_synthezier(synthesize_vovocov_expression3) |
| register_synthezier(synthesize_vocovov_expression3) |
| register_synthezier(synthesize_covovov_expression3) |
| register_synthezier(synthesize_covocov_expression3) |
| register_synthezier(synthesize_vocovoc_expression3) |
| register_synthezier(synthesize_covovoc_expression3) |
| register_synthezier(synthesize_vococov_expression3) |
| |
| register_synthezier(synthesize_vovovov_expression4) |
| register_synthezier(synthesize_vovovoc_expression4) |
| register_synthezier(synthesize_vovocov_expression4) |
| register_synthezier(synthesize_vocovov_expression4) |
| register_synthezier(synthesize_covovov_expression4) |
| register_synthezier(synthesize_covocov_expression4) |
| register_synthezier(synthesize_vocovoc_expression4) |
| register_synthezier(synthesize_covovoc_expression4) |
| #endif |
| } |
| |
| inline void set_parser(parser_t& p) |
| { |
| parser_ = &p; |
| } |
| |
| inline void set_uom(unary_op_map_t& unary_op_map) |
| { |
| unary_op_map_ = &unary_op_map; |
| } |
| |
| inline void set_bom(binary_op_map_t& binary_op_map) |
| { |
| binary_op_map_ = &binary_op_map; |
| } |
| |
| inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) |
| { |
| inv_binary_op_map_ = &inv_binary_op_map; |
| } |
| |
| inline void set_sf3m(sf3_map_t& sf3_map) |
| { |
| sf3_map_ = &sf3_map; |
| } |
| |
| inline void set_sf4m(sf4_map_t& sf4_map) |
| { |
| sf4_map_ = &sf4_map; |
| } |
| |
| inline void set_allocator(details::node_allocator& na) |
| { |
| node_allocator_ = &na; |
| } |
| |
| inline void set_strength_reduction_state(const bool enabled) |
| { |
| strength_reduction_enabled_ = enabled; |
| } |
| |
| inline bool strength_reduction_enabled() const |
| { |
| return strength_reduction_enabled_; |
| } |
| |
| inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) |
| { |
| typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); |
| |
| if ((*binary_op_map_).end() == bop_itr) |
| return false; |
| |
| bop = bop_itr->second; |
| |
| return true; |
| } |
| |
| inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) |
| { |
| typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); |
| |
| if ((*unary_op_map_).end() == uop_itr) |
| return false; |
| |
| uop = uop_itr->second; |
| |
| return true; |
| } |
| |
| inline details::operator_type get_operator(const binary_functor_t& bop) |
| { |
| return (*inv_binary_op_map_).find(bop)->second; |
| } |
| |
| inline expression_node_ptr operator()(const Type& v) const |
| { |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr operator()(const std::string& s) const |
| { |
| return node_allocator_->allocate<string_literal_node_t>(s); |
| } |
| |
| inline expression_node_ptr operator()(std::string& s, range_t& rp) const |
| { |
| return node_allocator_->allocate_rr<string_range_node_t>(s,rp); |
| } |
| |
| inline expression_node_ptr operator()(const std::string& s, range_t& rp) const |
| { |
| return node_allocator_->allocate_tt<const_string_range_node_t>(s,rp); |
| } |
| |
| inline expression_node_ptr operator()(expression_node_ptr branch, range_t& rp) const |
| { |
| if (is_generally_string_node(branch)) |
| return node_allocator_->allocate_tt<generic_string_range_node_t>(branch,rp); |
| else |
| return error_node(); |
| } |
| #endif |
| |
| inline bool unary_optimisable(const details::operator_type& operation) const |
| { |
| return (details::e_abs == operation) || (details::e_acos == operation) || |
| (details::e_acosh == operation) || (details::e_asin == operation) || |
| (details::e_asinh == operation) || (details::e_atan == operation) || |
| (details::e_atanh == operation) || (details::e_ceil == operation) || |
| (details::e_cos == operation) || (details::e_cosh == operation) || |
| (details::e_exp == operation) || (details::e_expm1 == operation) || |
| (details::e_floor == operation) || (details::e_log == operation) || |
| (details::e_log10 == operation) || (details::e_log2 == operation) || |
| (details::e_log1p == operation) || (details::e_neg == operation) || |
| (details::e_pos == operation) || (details::e_round == operation) || |
| (details::e_sin == operation) || (details::e_sinc == operation) || |
| (details::e_sinh == operation) || (details::e_sqrt == operation) || |
| (details::e_tan == operation) || (details::e_tanh == operation) || |
| (details::e_cot == operation) || (details::e_sec == operation) || |
| (details::e_csc == operation) || (details::e_r2d == operation) || |
| (details::e_d2r == operation) || (details::e_d2g == operation) || |
| (details::e_g2d == operation) || (details::e_notl == operation) || |
| (details::e_sgn == operation) || (details::e_erf == operation) || |
| (details::e_erfc == operation) || (details::e_ncdf == operation) || |
| (details::e_frac == operation) || (details::e_trunc == operation); |
| } |
| |
| inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) |
| { |
| typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); |
| |
| if (sf3_map_->end() == itr) |
| return false; |
| else |
| tfunc = itr->second.first; |
| |
| return true; |
| } |
| |
| inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) |
| { |
| typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); |
| |
| if (sf4_map_->end() == itr) |
| return false; |
| else |
| qfunc = itr->second.first; |
| |
| return true; |
| } |
| |
| inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) |
| { |
| typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); |
| |
| if (sf3_map_->end() == itr) |
| return false; |
| else |
| operation = itr->second.second; |
| |
| return true; |
| } |
| |
| inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) |
| { |
| typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); |
| |
| if (sf4_map_->end() == itr) |
| return false; |
| else |
| operation = itr->second.second; |
| |
| return true; |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1]) |
| { |
| if (0 == branch[0]) |
| return error_node(); |
| else if (details::is_null_node(branch[0])) |
| return branch[0]; |
| else if (details::is_break_node(branch[0])) |
| return error_node(); |
| else if (details::is_continue_node(branch[0])) |
| return error_node(); |
| else if (details::is_constant_node(branch[0])) |
| return synthesize_expression<unary_node_t,1>(operation,branch); |
| else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) |
| return synthesize_uv_expression(operation,branch); |
| else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) |
| return synthesize_uvec_expression(operation,branch); |
| else |
| return synthesize_unary_expression(operation,branch); |
| } |
| |
| inline bool is_assignment_operation(const details::operator_type& operation) const |
| { |
| return ( |
| (details::e_addass == operation) || |
| (details::e_subass == operation) || |
| (details::e_mulass == operation) || |
| (details::e_divass == operation) || |
| (details::e_modass == operation) |
| ) && |
| parser_->settings_.assignment_enabled(operation); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline bool valid_string_operation(const details::operator_type& operation) const |
| { |
| return (details::e_add == 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_in == operation) || |
| (details::e_like == operation) || |
| (details::e_ilike == operation) || |
| (details::e_assign == operation) || |
| (details::e_addass == operation) || |
| (details::e_swap == operation) ; |
| } |
| #else |
| inline bool valid_string_operation(const details::operator_type&) const |
| { |
| return false; |
| } |
| #endif |
| |
| inline std::string to_str(const details::operator_type& operation) const |
| { |
| switch (operation) |
| { |
| case details::e_add : return "+"; |
| case details::e_sub : return "-"; |
| case details::e_mul : return "*"; |
| case details::e_div : return "/"; |
| case details::e_mod : return "%"; |
| case details::e_pow : return "^"; |
| case details::e_lt : return "<"; |
| case details::e_lte : return "<="; |
| case details::e_gt : return ">"; |
| case details::e_gte : return ">="; |
| case details::e_eq : return "=="; |
| case details::e_ne : return "!="; |
| case details::e_and : return "and"; |
| case details::e_nand : return "nand"; |
| case details::e_or : return "or"; |
| case details::e_nor : return "nor"; |
| case details::e_xor : return "xor"; |
| case details::e_xnor : return "xnor"; |
| default : return "UNKNOWN"; |
| } |
| } |
| |
| inline bool operation_optimisable(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) || |
| (details::e_xnor == operation) ; |
| } |
| |
| inline std::string branch_to_id(expression_node_ptr branch) |
| { |
| static const std::string null_str ("(null)" ); |
| static const std::string const_str ("(c)" ); |
| static const std::string var_str ("(v)" ); |
| static const std::string vov_str ("(vov)" ); |
| static const std::string cov_str ("(cov)" ); |
| static const std::string voc_str ("(voc)" ); |
| static const std::string str_str ("(s)" ); |
| static const std::string strrng_str ("(rngs)" ); |
| static const std::string cs_str ("(cs)" ); |
| static const std::string cstrrng_str("(crngs)"); |
| |
| if (details::is_null_node(branch)) |
| return null_str; |
| else if (details::is_constant_node(branch)) |
| return const_str; |
| else if (details::is_variable_node(branch)) |
| return var_str; |
| else if (details::is_vov_node(branch)) |
| return vov_str; |
| else if (details::is_cov_node(branch)) |
| return cov_str; |
| else if (details::is_voc_node(branch)) |
| return voc_str; |
| else if (details::is_string_node(branch)) |
| return str_str; |
| else if (details::is_const_string_node(branch)) |
| return cs_str; |
| else if (details::is_string_range_node(branch)) |
| return strrng_str; |
| else if (details::is_const_string_range_node(branch)) |
| return cstrrng_str; |
| else if (details::is_t0ot1ot2_node(branch)) |
| return "(" + dynamic_cast<details::T0oT1oT2_base_node<T>*>(branch)->type_id() + ")"; |
| else if (details::is_t0ot1ot2ot3_node(branch)) |
| return "(" + dynamic_cast<details::T0oT1oT2oT3_base_node<T>*>(branch)->type_id() + ")"; |
| else |
| return "ERROR"; |
| } |
| |
| inline std::string branch_to_id(expression_node_ptr (&branch)[2]) |
| { |
| return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); |
| } |
| |
| inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); |
| } |
| |
| inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); |
| } |
| |
| inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); |
| } |
| |
| inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); |
| } |
| |
| inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); |
| } |
| |
| inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || |
| (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])); |
| } |
| else |
| return false; |
| } |
| |
| inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || |
| (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])); |
| } |
| else |
| return false; |
| } |
| |
| inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); |
| } |
| |
| inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); |
| } |
| |
| inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); |
| } |
| |
| inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const |
| { |
| if (!operation_optimisable(operation)) |
| return false; |
| else |
| return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); |
| } |
| |
| inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| if (is_assignment_operation(operation)) |
| { |
| const bool b1_is_genstring = details::is_generally_string_node(branch[1]); |
| |
| if (details::is_string_node(branch[0])) |
| return !b1_is_genstring; |
| else |
| return ( |
| !details::is_variable_node (branch[0]) && |
| !details::is_vector_elem_node (branch[0]) && |
| !details::is_rebasevector_elem_node (branch[0]) && |
| !details::is_rebasevector_celem_node(branch[0]) && |
| !details::is_vector_node (branch[0]) |
| ) |
| || b1_is_genstring; |
| } |
| else |
| return false; |
| } |
| |
| inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) |
| { |
| if ( |
| !is_constant_node(branch[1]) || |
| is_constant_node(branch[0]) || |
| is_variable_node(branch[0]) || |
| is_vector_node (branch[0]) || |
| is_generally_string_node(branch[0]) |
| ) |
| return false; |
| |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| |
| return cardinal_pow_optimisable(operation, c); |
| } |
| |
| inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) |
| { |
| return ( |
| details::is_break_node (branch[0]) || |
| details::is_break_node (branch[1]) || |
| details::is_continue_node(branch[0]) || |
| details::is_continue_node(branch[1]) |
| ); |
| } |
| |
| inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| const bool b0_string = is_generally_string_node(branch[0]); |
| const bool b1_string = is_generally_string_node(branch[1]); |
| |
| bool result = false; |
| |
| if (b0_string != b1_string) |
| result = true; |
| else if (!valid_string_operation(operation) && b0_string && b1_string) |
| result = true; |
| |
| if (result) |
| { |
| parser_->set_synthesis_error("Invalid string operation"); |
| } |
| |
| return result; |
| } |
| |
| inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) |
| { |
| const bool b0_string = is_generally_string_node(branch[0]); |
| const bool b1_string = is_generally_string_node(branch[1]); |
| const bool b2_string = is_generally_string_node(branch[2]); |
| |
| bool result = false; |
| |
| if ((b0_string != b1_string) || (b1_string != b2_string)) |
| result = true; |
| else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) |
| result = true; |
| |
| if (result) |
| { |
| parser_->set_synthesis_error("Invalid string operation"); |
| } |
| |
| return result; |
| } |
| |
| inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| const bool b0_string = is_generally_string_node(branch[0]); |
| const bool b1_string = is_generally_string_node(branch[1]); |
| |
| return (b0_string && b1_string && valid_string_operation(operation)); |
| } |
| |
| inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) |
| { |
| const bool b0_string = is_generally_string_node(branch[0]); |
| const bool b1_string = is_generally_string_node(branch[1]); |
| const bool b2_string = is_generally_string_node(branch[2]); |
| |
| return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); |
| } |
| |
| #ifndef exprtk_disable_sc_andor |
| inline bool is_shortcircuit_expression(const details::operator_type& operation) |
| { |
| return ( |
| (details::e_scand == operation) || |
| (details::e_scor == operation) |
| ); |
| } |
| #else |
| inline bool is_shortcircuit_expression(const details::operator_type&) |
| { |
| return false; |
| } |
| #endif |
| |
| inline bool is_null_present(expression_node_ptr (&branch)[2]) |
| { |
| return ( |
| details::is_null_node(branch[0]) || |
| details::is_null_node(branch[1]) |
| ); |
| } |
| |
| inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) |
| return false; |
| else |
| 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) || |
| (details::e_equal == operation) || |
| (details::e_and == operation) || |
| (details::e_nand == operation) || |
| (details:: e_or == operation) || |
| (details:: e_nor == operation) || |
| (details:: e_xor == operation) || |
| (details::e_xnor == operation) |
| ); |
| } |
| |
| inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) |
| return false; |
| else |
| return ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) || |
| (details::e_pow == operation) |
| ); |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| if ((0 == branch[0]) || (0 == branch[1])) |
| return error_node(); |
| else if (is_invalid_string_op(operation,branch)) |
| return error_node(); |
| else if (is_invalid_assignment_op(operation,branch)) |
| return error_node(); |
| else if (is_invalid_break_continue_op(branch)) |
| return error_node(); |
| else if (details::e_assign == operation) |
| return synthesize_assignment_expression(operation,branch); |
| else if (details::e_swap == operation) |
| return synthesize_swap_expression(branch); |
| else if (is_assignment_operation(operation)) |
| return synthesize_assignment_operation_expression(operation,branch); |
| else if (is_vector_eqineq_logic_operation(operation,branch)) |
| return synthesize_veceqineqlogic_operation_expression(operation,branch); |
| else if (is_vector_arithmetic_operation(operation,branch)) |
| return synthesize_vecarithmetic_operation_expression(operation,branch); |
| else if (is_shortcircuit_expression(operation)) |
| return synthesize_shortcircuit_expression(operation,branch); |
| else if (is_string_operation(operation,branch)) |
| return synthesize_string_expression(operation,branch); |
| else if (is_null_present(branch)) |
| return synthesize_null_expression(operation, branch); |
| #ifndef exprtk_disable_cardinal_pow_optimisation |
| else if (is_constpow_operation(operation, branch)) |
| return cardinal_pow_optimisation(branch); |
| #endif |
| |
| expression_node_ptr result = error_node(); |
| |
| #ifndef exprtk_disable_enhanced_features |
| if (synthesize_expression(operation,branch,result)) |
| return result; |
| else |
| #endif |
| |
| { |
| /* |
| Possible reductions: |
| 1. c o cob -> cob |
| 2. cob o c -> cob |
| 3. c o boc -> boc |
| 4. boc o c -> boc |
| */ |
| result = error_node(); |
| |
| if (cocob_optimisable(operation,branch)) |
| result = synthesize_cocob_expression::process(*this,operation,branch); |
| else if (coboc_optimisable(operation,branch) && (0 == result)) |
| result = synthesize_coboc_expression::process(*this,operation,branch); |
| |
| if (result) |
| return result; |
| } |
| |
| if (uvouv_optimisable(operation,branch)) |
| return synthesize_uvouv_expression(operation,branch); |
| else if (vob_optimisable(operation,branch)) |
| return synthesize_vob_expression::process(*this,operation,branch); |
| else if (bov_optimisable(operation,branch)) |
| return synthesize_bov_expression::process(*this,operation,branch); |
| else if (cob_optimisable(operation,branch)) |
| return synthesize_cob_expression::process(*this,operation,branch); |
| else if (boc_optimisable(operation,branch)) |
| return synthesize_boc_expression::process(*this,operation,branch); |
| #ifndef exprtk_disable_enhanced_features |
| else if (cov_optimisable(operation,branch)) |
| return synthesize_cov_expression::process(*this,operation,branch); |
| #endif |
| else if (binext_optimisable(operation,branch)) |
| return synthesize_binary_ext_expression::process(*this,operation,branch); |
| else |
| return synthesize_expression<binary_node_t,2>(operation,branch); |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) |
| { |
| if ( |
| (0 == branch[0]) || |
| (0 == branch[1]) || |
| (0 == branch[2]) |
| ) |
| { |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if (is_invalid_string_op(operation,branch)) |
| return error_node(); |
| else if (is_string_operation(operation,branch)) |
| return synthesize_string_expression(operation,branch); |
| else |
| return synthesize_expression<trinary_node_t,3>(operation,branch); |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) |
| { |
| return synthesize_expression<quaternary_node_t,4>(operation,branch); |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0) |
| { |
| expression_node_ptr branch[1] = { b0 }; |
| return (*this)(operation,branch); |
| } |
| |
| inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) |
| { |
| if ((0 == b0) || (0 == b1)) |
| return error_node(); |
| else |
| { |
| expression_node_ptr branch[2] = { b0, b1 }; |
| return expression_generator<Type>::operator()(operation,branch); |
| } |
| } |
| |
| inline expression_node_ptr conditional(expression_node_ptr condition, |
| expression_node_ptr consequent, |
| expression_node_ptr alternative) const |
| { |
| if ((0 == condition) || (0 == consequent)) |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,consequent ); |
| free_node(*node_allocator_,alternative); |
| |
| return error_node(); |
| } |
| // Can the condition be immediately evaluated? if so optimise. |
| else if (details::is_constant_node(condition)) |
| { |
| // True branch |
| if (details::is_true(condition)) |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,alternative); |
| |
| return consequent; |
| } |
| // False branch |
| else |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,consequent); |
| |
| if (alternative) |
| return alternative; |
| else |
| return node_allocator_->allocate<details::null_node<T> >(); |
| } |
| } |
| else if ((0 != consequent) && (0 != alternative)) |
| { |
| return node_allocator_-> |
| allocate<conditional_node_t>(condition,consequent,alternative); |
| } |
| else |
| return node_allocator_-> |
| allocate<cons_conditional_node_t>(condition,consequent); |
| } |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr conditional_string(expression_node_ptr condition, |
| expression_node_ptr consequent, |
| expression_node_ptr alternative) const |
| { |
| if ((0 == condition) || (0 == consequent)) |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,consequent ); |
| free_node(*node_allocator_,alternative); |
| |
| return error_node(); |
| } |
| // Can the condition be immediately evaluated? if so optimise. |
| else if (details::is_constant_node(condition)) |
| { |
| // True branch |
| if (details::is_true(condition)) |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,alternative); |
| |
| return consequent; |
| } |
| // False branch |
| else |
| { |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,consequent); |
| |
| if (alternative) |
| return alternative; |
| else |
| return node_allocator_-> |
| allocate_c<details::string_literal_node<Type> >(""); |
| } |
| } |
| else if ((0 != consequent) && (0 != alternative)) |
| return node_allocator_-> |
| allocate<conditional_string_node_t>(condition,consequent,alternative); |
| else |
| return error_node(); |
| } |
| #else |
| inline expression_node_ptr conditional_string(expression_node_ptr, |
| expression_node_ptr, |
| expression_node_ptr) const |
| { |
| return error_node(); |
| } |
| #endif |
| |
| inline expression_node_ptr while_loop(expression_node_ptr& condition, |
| expression_node_ptr& branch, |
| const bool brkcont = false) const |
| { |
| if (!brkcont && details::is_constant_node(condition)) |
| { |
| expression_node_ptr result = error_node(); |
| if (details::is_true(condition)) |
| // Infinite loops are not allowed. |
| result = error_node(); |
| else |
| result = node_allocator_->allocate<details::null_node<Type> >(); |
| |
| free_node(*node_allocator_, condition); |
| free_node(*node_allocator_, branch ); |
| |
| return result; |
| } |
| else if (details::is_null_node(condition)) |
| { |
| free_node(*node_allocator_,condition); |
| |
| return branch; |
| } |
| else if (!brkcont) |
| return node_allocator_->allocate<while_loop_node_t>(condition,branch); |
| #ifndef exprtk_disable_break_continue |
| else |
| return node_allocator_->allocate<while_loop_bc_node_t>(condition,branch); |
| #else |
| return error_node(); |
| #endif |
| } |
| |
| inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, |
| expression_node_ptr& branch, |
| const bool brkcont = false) const |
| { |
| if (!brkcont && details::is_constant_node(condition)) |
| { |
| if (details::is_true(condition) && details::is_constant_node(branch)) |
| { |
| free_node(*node_allocator_,condition); |
| |
| return branch; |
| } |
| |
| free_node(*node_allocator_, condition); |
| free_node(*node_allocator_, branch ); |
| |
| return error_node(); |
| } |
| else if (details::is_null_node(condition)) |
| { |
| free_node(*node_allocator_,condition); |
| |
| return branch; |
| } |
| else if (!brkcont) |
| return node_allocator_->allocate<repeat_until_loop_node_t>(condition,branch); |
| #ifndef exprtk_disable_break_continue |
| else |
| return node_allocator_->allocate<repeat_until_loop_bc_node_t>(condition,branch); |
| #else |
| return error_node(); |
| #endif |
| } |
| |
| inline expression_node_ptr for_loop(expression_node_ptr& initialiser, |
| expression_node_ptr& condition, |
| expression_node_ptr& incrementor, |
| expression_node_ptr& loop_body, |
| bool brkcont = false) const |
| { |
| if (!brkcont && details::is_constant_node(condition)) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (details::is_true(condition)) |
| // Infinite loops are not allowed. |
| result = error_node(); |
| else |
| result = node_allocator_->allocate<details::null_node<Type> >(); |
| |
| free_node(*node_allocator_,initialiser); |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,incrementor); |
| free_node(*node_allocator_,loop_body ); |
| |
| return result; |
| } |
| else if (details::is_null_node(condition)) |
| { |
| free_node(*node_allocator_,initialiser); |
| free_node(*node_allocator_,condition ); |
| free_node(*node_allocator_,incrementor); |
| |
| return loop_body; |
| } |
| else if (!brkcont) |
| return node_allocator_->allocate<for_loop_node_t>(initialiser, |
| condition, |
| incrementor, |
| loop_body); |
| #ifndef exprtk_disable_break_continue |
| else |
| return node_allocator_->allocate<for_loop_bc_node_t>(initialiser, |
| condition, |
| incrementor, |
| loop_body); |
| #else |
| return error_node(); |
| #endif |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr const_optimise_switch(Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| expression_node_ptr result = error_node(); |
| |
| for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) |
| { |
| expression_node_ptr condition = arg_list[(2 * i) ]; |
| expression_node_ptr consequent = arg_list[(2 * i) + 1]; |
| |
| if ((0 == result) && details::is_true(condition)) |
| { |
| result = consequent; |
| break; |
| } |
| } |
| |
| if (0 == result) |
| { |
| result = arg_list.back(); |
| } |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| expression_node_ptr current_expr = arg_list[i]; |
| |
| if (current_expr && (current_expr != result)) |
| { |
| free_node(*node_allocator_,current_expr); |
| } |
| } |
| |
| return result; |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr const_optimise_mswitch(Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| expression_node_ptr result = error_node(); |
| |
| for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) |
| { |
| expression_node_ptr condition = arg_list[(2 * i) ]; |
| expression_node_ptr consequent = arg_list[(2 * i) + 1]; |
| |
| if (details::is_true(condition)) |
| { |
| result = consequent; |
| } |
| } |
| |
| if (0 == result) |
| { |
| T zero = T(0); |
| result = node_allocator_->allocate<literal_node_t>(zero); |
| } |
| |
| for (std::size_t i = 0; i < arg_list.size(); ++i) |
| { |
| expression_node_ptr& current_expr = arg_list[i]; |
| |
| if (current_expr && (current_expr != result)) |
| { |
| free_node(*node_allocator_,current_expr); |
| } |
| } |
| |
| return result; |
| } |
| |
| struct switch_nodes |
| { |
| typedef std::vector<expression_node_ptr> arg_list_t; |
| |
| #define case_stmt(N) \ |
| if (is_true(arg[(2 * N)])) { return arg[(2 * N) + 1]->value(); } \ |
| |
| struct switch_1 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_2 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_3 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| case_stmt(2) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_4 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| case_stmt(2) case_stmt(3) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_5 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| case_stmt(2) case_stmt(3) |
| case_stmt(4) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_6 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| case_stmt(2) case_stmt(3) |
| case_stmt(4) case_stmt(5) |
| return arg.back()->value(); |
| } |
| }; |
| |
| struct switch_7 |
| { |
| static inline T process(const arg_list_t& arg) |
| { |
| case_stmt(0) case_stmt(1) |
| case_stmt(2) case_stmt(3) |
| case_stmt(4) case_stmt(5) |
| case_stmt(6) |
| return arg.back()->value(); |
| } |
| }; |
| |
| #undef case_stmt |
| }; |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| if (arg_list.empty()) |
| return error_node(); |
| else if ( |
| !all_nodes_valid(arg_list) || |
| (arg_list.size() < 3) || |
| ((arg_list.size() % 2) != 1) |
| ) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| else if (is_constant_foldable(arg_list)) |
| return const_optimise_switch(arg_list); |
| |
| switch ((arg_list.size() - 1) / 2) |
| { |
| #define case_stmt(N) \ |
| case N : \ |
| return node_allocator_-> \ |
| allocate<details::switch_n_node \ |
| <Type,typename switch_nodes::switch_##N> >(arg_list); \ |
| |
| case_stmt(1) |
| case_stmt(2) |
| case_stmt(3) |
| case_stmt(4) |
| case_stmt(5) |
| case_stmt(6) |
| case_stmt(7) |
| #undef case_stmt |
| |
| default : return node_allocator_->allocate<details::switch_node<Type> >(arg_list); |
| } |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr multi_switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| else if (is_constant_foldable(arg_list)) |
| return const_optimise_mswitch(arg_list); |
| else |
| return node_allocator_->allocate<details::multi_switch_node<Type> >(arg_list); |
| } |
| |
| #define unary_opr_switch_statements \ |
| case_stmt(details:: e_abs,details:: abs_op) \ |
| case_stmt(details:: e_acos,details:: acos_op) \ |
| case_stmt(details::e_acosh,details::acosh_op) \ |
| case_stmt(details:: e_asin,details:: asin_op) \ |
| case_stmt(details::e_asinh,details::asinh_op) \ |
| case_stmt(details:: e_atan,details:: atan_op) \ |
| case_stmt(details::e_atanh,details::atanh_op) \ |
| case_stmt(details:: e_ceil,details:: ceil_op) \ |
| case_stmt(details:: e_cos,details:: cos_op) \ |
| case_stmt(details:: e_cosh,details:: cosh_op) \ |
| case_stmt(details:: e_exp,details:: exp_op) \ |
| case_stmt(details::e_expm1,details::expm1_op) \ |
| case_stmt(details::e_floor,details::floor_op) \ |
| case_stmt(details:: e_log,details:: log_op) \ |
| case_stmt(details::e_log10,details::log10_op) \ |
| case_stmt(details:: e_log2,details:: log2_op) \ |
| case_stmt(details::e_log1p,details::log1p_op) \ |
| case_stmt(details:: e_neg,details:: neg_op) \ |
| case_stmt(details:: e_pos,details:: pos_op) \ |
| case_stmt(details::e_round,details::round_op) \ |
| case_stmt(details:: e_sin,details:: sin_op) \ |
| case_stmt(details:: e_sinc,details:: sinc_op) \ |
| case_stmt(details:: e_sinh,details:: sinh_op) \ |
| case_stmt(details:: e_sqrt,details:: sqrt_op) \ |
| case_stmt(details:: e_tan,details:: tan_op) \ |
| case_stmt(details:: e_tanh,details:: tanh_op) \ |
| case_stmt(details:: e_cot,details:: cot_op) \ |
| case_stmt(details:: e_sec,details:: sec_op) \ |
| case_stmt(details:: e_csc,details:: csc_op) \ |
| case_stmt(details:: e_r2d,details:: r2d_op) \ |
| case_stmt(details:: e_d2r,details:: d2r_op) \ |
| case_stmt(details:: e_d2g,details:: d2g_op) \ |
| case_stmt(details:: e_g2d,details:: g2d_op) \ |
| case_stmt(details:: e_notl,details:: notl_op) \ |
| case_stmt(details:: e_sgn,details:: sgn_op) \ |
| case_stmt(details:: e_erf,details:: erf_op) \ |
| case_stmt(details:: e_erfc,details:: erfc_op) \ |
| case_stmt(details:: e_ncdf,details:: ncdf_op) \ |
| case_stmt(details:: e_frac,details:: frac_op) \ |
| case_stmt(details::e_trunc,details::trunc_op) \ |
| |
| inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[1]) |
| { |
| T& v = static_cast<details::variable_node<T>*>(branch[0])->ref(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<typename details::unary_variable_node<Type,op1<Type> > >(v); \ |
| |
| unary_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[1]) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<typename details::unary_vector_node<Type,op1<Type> > > \ |
| (operation,branch[0]); \ |
| |
| unary_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[1]) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<typename details::unary_branch_node<Type,op1<Type> > >(branch[0]); \ |
| |
| unary_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, |
| expression_node_ptr (&branch)[3]) |
| { |
| expression_node_ptr temp_node = error_node(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : temp_node = node_allocator_-> \ |
| allocate<details::sf3_node<Type,details::sf##op##_op<Type> > > \ |
| (operation,branch); \ |
| break; \ |
| |
| case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) |
| case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) |
| case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) |
| case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) |
| case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) |
| case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) |
| case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) |
| case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) |
| case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) |
| case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) |
| case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) |
| case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| |
| T v = temp_node->value(); |
| |
| details::free_node(*node_allocator_,temp_node); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) |
| { |
| typedef details::variable_node<Type>* variable_ptr; |
| |
| const Type& v0 = static_cast<variable_ptr>(branch[0])->ref(); |
| const Type& v1 = static_cast<variable_ptr>(branch[1])->ref(); |
| const Type& v2 = static_cast<variable_ptr>(branch[2])->ref(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : return node_allocator_-> \ |
| allocate_rrr<details::sf3_var_node<Type,details::sf##op##_op<Type> > > \ |
| (v0,v1,v2); \ |
| |
| case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) |
| case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) |
| case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) |
| case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) |
| case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) |
| case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) |
| case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) |
| case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) |
| case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) |
| case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) |
| case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) |
| case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) |
| { |
| if (!all_nodes_valid(branch)) |
| return error_node(); |
| else if (is_constant_foldable(branch)) |
| return const_optimise_sf3(operation,branch); |
| else if (all_nodes_variables(branch)) |
| return varnode_optimise_sf3(operation,branch); |
| else |
| { |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : return node_allocator_-> \ |
| allocate<details::sf3_node<Type,details::sf##op##_op<Type> > > \ |
| (operation,branch); \ |
| |
| case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) |
| case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) |
| case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) |
| case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) |
| case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) |
| case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) |
| case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) |
| case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) |
| case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) |
| case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) |
| case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) |
| case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| } |
| |
| inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) |
| { |
| expression_node_ptr temp_node = error_node(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : temp_node = node_allocator_-> \ |
| allocate<details::sf4_node<Type,details::sf##op##_op<Type> > > \ |
| (operation,branch); \ |
| break; \ |
| |
| case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) |
| case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) |
| case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) |
| case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) |
| case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) |
| case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) |
| case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) |
| case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) |
| case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) |
| case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) |
| case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) |
| case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) |
| case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| |
| T v = temp_node->value(); |
| details::free_node(*node_allocator_,temp_node); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) |
| { |
| typedef details::variable_node<Type>* variable_ptr; |
| |
| const Type& v0 = static_cast<variable_ptr>(branch[0])->ref(); |
| const Type& v1 = static_cast<variable_ptr>(branch[1])->ref(); |
| const Type& v2 = static_cast<variable_ptr>(branch[2])->ref(); |
| const Type& v3 = static_cast<variable_ptr>(branch[3])->ref(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : return node_allocator_-> \ |
| allocate_rrrr<details::sf4_var_node<Type,details::sf##op##_op<Type> > > \ |
| (v0,v1,v2,v3); \ |
| |
| case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) |
| case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) |
| case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) |
| case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) |
| case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) |
| case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) |
| case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) |
| case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) |
| case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) |
| case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) |
| case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) |
| case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) |
| case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) |
| { |
| if (!all_nodes_valid(branch)) |
| return error_node(); |
| else if (is_constant_foldable(branch)) |
| return const_optimise_sf4(operation,branch); |
| else if (all_nodes_variables(branch)) |
| return varnode_optimise_sf4(operation,branch); |
| switch (operation) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : return node_allocator_-> \ |
| allocate<details::sf4_node<Type,details::sf##op##_op<Type> > > \ |
| (operation,branch); \ |
| |
| case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) |
| case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) |
| case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) |
| case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) |
| case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) |
| case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) |
| case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) |
| case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) |
| case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) |
| case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) |
| case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) |
| case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) |
| case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| expression_node_ptr temp_node = error_node(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : temp_node = node_allocator_-> \ |
| allocate<details::vararg_node<Type,op1<Type> > > \ |
| (arg_list); \ |
| break; \ |
| |
| case_stmt(details::e_sum, details::vararg_add_op ) |
| case_stmt(details::e_prod, details::vararg_mul_op ) |
| case_stmt(details::e_avg, details::vararg_avg_op ) |
| case_stmt(details::e_min, details::vararg_min_op ) |
| case_stmt(details::e_max, details::vararg_max_op ) |
| case_stmt(details::e_mand, details::vararg_mand_op ) |
| case_stmt(details::e_mor, details::vararg_mor_op ) |
| case_stmt(details::e_multi,details::vararg_multi_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| |
| T v = temp_node->value(); |
| details::free_node(*node_allocator_,temp_node); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| inline bool special_one_parameter_vararg(const details::operator_type& operation) |
| { |
| return ( |
| (details::e_sum == operation) || |
| (details::e_prod == operation) || |
| (details::e_avg == operation) || |
| (details::e_min == operation) || |
| (details::e_max == operation) |
| ); |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<details::vararg_varnode<Type,op1<Type> > >(arg_list); \ |
| |
| case_stmt(details::e_sum, details::vararg_add_op ) |
| case_stmt(details::e_prod, details::vararg_mul_op ) |
| case_stmt(details::e_avg, details::vararg_avg_op ) |
| case_stmt(details::e_min, details::vararg_min_op ) |
| case_stmt(details::e_max, details::vararg_max_op ) |
| case_stmt(details::e_mand, details::vararg_mand_op ) |
| case_stmt(details::e_mor, details::vararg_mor_op ) |
| case_stmt(details::e_multi,details::vararg_multi_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| if (1 == arg_list.size()) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<details::vectorize_node<Type,op1<Type> > >(arg_list[0]); \ |
| |
| case_stmt(details::e_sum, details::vec_add_op) |
| case_stmt(details::e_prod, details::vec_mul_op) |
| case_stmt(details::e_avg, details::vec_avg_op) |
| case_stmt(details::e_min, details::vec_min_op) |
| case_stmt(details::e_max, details::vec_max_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else |
| return error_node(); |
| } |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| else if (is_constant_foldable(arg_list)) |
| return const_optimise_varargfunc(operation,arg_list); |
| else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) |
| return vectorize_func(operation,arg_list); |
| else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) |
| return arg_list[0]; |
| else if (all_nodes_variables(arg_list)) |
| return varnode_optimise_varargfunc(operation,arg_list); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate<details::vararg_node<Type,op1<Type> > >(arg_list); \ |
| |
| case_stmt(details::e_sum, details::vararg_add_op ) |
| case_stmt(details::e_prod, details::vararg_mul_op ) |
| case_stmt(details::e_avg, details::vararg_avg_op ) |
| case_stmt(details::e_min, details::vararg_min_op ) |
| case_stmt(details::e_max, details::vararg_max_op ) |
| case_stmt(details::e_mand, details::vararg_mand_op ) |
| case_stmt(details::e_mor, details::vararg_mor_op ) |
| case_stmt(details::e_multi,details::vararg_multi_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <std::size_t N> |
| inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) |
| { |
| typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t; |
| expression_node_ptr result = synthesize_expression<function_N_node_t,N>(f,b); |
| |
| if (0 == result) |
| return error_node(); |
| else |
| { |
| // Can the function call be completely optimised? |
| if (details::is_constant_node(result)) |
| return result; |
| else if (!all_nodes_valid(b)) |
| return error_node(); |
| else if (N != f->param_count) |
| { |
| details::free_all_nodes(*node_allocator_,b); |
| |
| return error_node(); |
| } |
| |
| function_N_node_t* func_node_ptr = static_cast<function_N_node_t*>(result); |
| |
| if (func_node_ptr->init_branches(b)) |
| return result; |
| else |
| { |
| details::free_all_nodes(*node_allocator_,b); |
| |
| return error_node(); |
| } |
| } |
| } |
| |
| inline expression_node_ptr function(ifunction_t* f) |
| { |
| typedef typename details::function_N_node<Type,ifunction_t,0> function_N_node_t; |
| return node_allocator_->allocate<function_N_node_t>(f); |
| } |
| |
| inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, |
| std::vector<expression_node_ptr>& arg_list) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| |
| typedef details::vararg_function_node<Type,ivararg_function_t> alloc_type; |
| |
| expression_node_ptr result = node_allocator_->allocate<alloc_type>(vaf,arg_list); |
| |
| if ( |
| !arg_list.empty() && |
| !vaf->has_side_effects() && |
| is_constant_foldable(arg_list) |
| ) |
| { |
| Type v = result->value(); |
| details::free_node(*node_allocator_,result); |
| result = node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| parser_->state_.activate_side_effect("vararg_function_call()"); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr generic_function_call(igeneric_function_t* gf, |
| std::vector<expression_node_ptr>& arg_list, |
| const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max()) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| return error_node(); |
| } |
| |
| typedef details::generic_function_node <Type,igeneric_function_t> alloc_type1; |
| typedef details::multimode_genfunction_node<Type,igeneric_function_t> alloc_type2; |
| |
| const std::size_t no_psi = std::numeric_limits<std::size_t>::max(); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (no_psi == param_seq_index) |
| result = node_allocator_->allocate<alloc_type1>(arg_list,gf); |
| else |
| result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list); |
| |
| alloc_type1* genfunc_node_ptr = static_cast<alloc_type1*>(result); |
| |
| if ( |
| !arg_list.empty() && |
| !gf->has_side_effects() && |
| is_constant_foldable(arg_list) |
| ) |
| { |
| genfunc_node_ptr->init_branches(); |
| Type v = result->value(); |
| details::free_node(*node_allocator_,result); |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| else if (genfunc_node_ptr->init_branches()) |
| { |
| parser_->state_.activate_side_effect("generic_function_call()"); |
| return result; |
| } |
| else |
| { |
| details::free_node(*node_allocator_,result); |
| details::free_all_nodes(*node_allocator_,arg_list); |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr string_function_call(igeneric_function_t* gf, |
| std::vector<expression_node_ptr>& arg_list, |
| const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max()) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| return error_node(); |
| } |
| |
| typedef details::string_function_node <Type,igeneric_function_t> alloc_type1; |
| typedef details::multimode_strfunction_node<Type,igeneric_function_t> alloc_type2; |
| |
| const std::size_t no_psi = std::numeric_limits<std::size_t>::max(); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (no_psi == param_seq_index) |
| result = node_allocator_->allocate<alloc_type1>(gf,arg_list); |
| else |
| result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list); |
| |
| alloc_type1* strfunc_node_ptr = static_cast<alloc_type1*>(result); |
| |
| if ( |
| !arg_list.empty() && |
| !gf->has_side_effects() && |
| is_constant_foldable(arg_list) |
| ) |
| { |
| strfunc_node_ptr->init_branches(); |
| |
| Type v = result->value(); |
| |
| details::free_node(*node_allocator_,result); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| else if (strfunc_node_ptr->init_branches()) |
| { |
| parser_->state_.activate_side_effect("string_function_call()"); |
| |
| return result; |
| } |
| else |
| { |
| details::free_node(*node_allocator_,result); |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr return_call(std::vector<expression_node_ptr>& arg_list) |
| { |
| if (!all_nodes_valid(arg_list)) |
| { |
| details::free_all_nodes(*node_allocator_,arg_list); |
| return error_node(); |
| } |
| |
| typedef details::return_node<Type> alloc_type; |
| |
| expression_node_ptr result = node_allocator_-> |
| allocate_rr<alloc_type>(arg_list,parser_->results_ctx()); |
| |
| alloc_type* return_node_ptr = static_cast<alloc_type*>(result); |
| |
| if (return_node_ptr->init_branches()) |
| { |
| parser_->state_.activate_side_effect("return_call()"); |
| |
| return result; |
| } |
| else |
| { |
| details::free_node(*node_allocator_,result); |
| details::free_all_nodes(*node_allocator_,arg_list); |
| |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr return_envelope(expression_node_ptr body, |
| results_context_t* rc, |
| bool*& return_invoked) |
| { |
| typedef details::return_envelope_node<Type> alloc_type; |
| |
| expression_node_ptr result = node_allocator_-> |
| allocate_cr<alloc_type>(body,(*rc)); |
| |
| return_invoked = static_cast<alloc_type*>(result)->retinvk_ptr(); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr vector_element(const std::string& symbol, |
| vector_holder_ptr vector_base, |
| expression_node_ptr index) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (details::is_constant_node(index)) |
| { |
| std::size_t i = static_cast<std::size_t>(details::numeric::to_int64(index->value())); |
| |
| details::free_node(*node_allocator_,index); |
| |
| if (vector_base->rebaseable()) |
| { |
| return node_allocator_->allocate<rebasevector_celem_node_t>(i,vector_base); |
| } |
| |
| scope_element& se = parser_->sem_.get_element(symbol,i); |
| |
| if (se.index == i) |
| { |
| result = se.var_node; |
| } |
| else |
| { |
| scope_element nse; |
| nse.name = symbol; |
| nse.active = true; |
| nse.ref_count = 1; |
| nse.type = scope_element::e_vecelem; |
| nse.index = i; |
| nse.depth = parser_->state_.scope_depth; |
| nse.data = 0; |
| nse.var_node = node_allocator_->allocate<variable_node_t>((*(*vector_base)[i])); |
| |
| if (!parser_->sem_.add_element(nse)) |
| { |
| parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); |
| |
| parser_->sem_.free_element(nse); |
| |
| result = error_node(); |
| } |
| |
| exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); |
| |
| parser_->state_.activate_side_effect("vector_element()"); |
| |
| result = nse.var_node; |
| } |
| } |
| else if (vector_base->rebaseable()) |
| result = node_allocator_->allocate<rebasevector_elem_node_t>(index,vector_base); |
| else |
| result = node_allocator_->allocate<vector_elem_node_t>(index,vector_base); |
| |
| return result; |
| } |
| |
| private: |
| |
| template <std::size_t N, typename NodePtr> |
| inline bool is_constant_foldable(NodePtr (&b)[N]) const |
| { |
| for (std::size_t i = 0; i < N; ++i) |
| { |
| if (0 == b[i]) |
| return false; |
| else if (!details::is_constant_node(b[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename NodePtr, |
| typename Allocator, |
| template <typename,typename> class Sequence> |
| inline bool is_constant_foldable(const Sequence<NodePtr,Allocator>& b) const |
| { |
| for (std::size_t i = 0; i < b.size(); ++i) |
| { |
| if (0 == b[i]) |
| return false; |
| else if (!details::is_constant_node(b[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void lodge_assignment(symbol_type cst, expression_node_ptr node) |
| { |
| parser_->state_.activate_side_effect("lodge_assignment()"); |
| |
| if (!parser_->dec_.collect_assignments()) |
| return; |
| |
| std::string symbol_name; |
| |
| switch (cst) |
| { |
| case e_st_variable : symbol_name = parser_->symtab_store_ |
| .get_variable_name(node); |
| break; |
| |
| #ifndef exprtk_disable_string_capabilities |
| case e_st_string : symbol_name = parser_->symtab_store_ |
| .get_stringvar_name(node); |
| break; |
| #endif |
| |
| case e_st_vector : { |
| typedef details::vector_holder<T> vector_holder_t; |
| |
| vector_holder_t& vh = static_cast<vector_node_t*>(node)->vec_holder(); |
| |
| symbol_name = parser_->symtab_store_.get_vector_name(&vh); |
| } |
| break; |
| |
| case e_st_vecelem : { |
| typedef details::vector_holder<T> vector_holder_t; |
| |
| vector_holder_t& vh = static_cast<vector_elem_node_t*>(node)->vec_holder(); |
| |
| symbol_name = parser_->symtab_store_.get_vector_name(&vh); |
| |
| cst = e_st_vector; |
| } |
| break; |
| |
| default : return; |
| } |
| |
| if (!symbol_name.empty()) |
| { |
| parser_->dec_.add_assignment(symbol_name,cst); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| if (details::is_variable_node(branch[0])) |
| { |
| lodge_assignment(e_st_variable,branch[0]); |
| |
| return synthesize_expression<assignment_node_t,2>(operation,branch); |
| } |
| else if (details::is_vector_elem_node(branch[0])) |
| { |
| lodge_assignment(e_st_vecelem,branch[0]); |
| |
| return synthesize_expression<assignment_vec_elem_node_t, 2>(operation, branch); |
| } |
| else if (details::is_rebasevector_elem_node(branch[0])) |
| { |
| lodge_assignment(e_st_vecelem,branch[0]); |
| |
| return synthesize_expression<assignment_rebasevec_elem_node_t, 2>(operation, branch); |
| } |
| else if (details::is_rebasevector_celem_node(branch[0])) |
| { |
| lodge_assignment(e_st_vecelem,branch[0]); |
| |
| return synthesize_expression<assignment_rebasevec_celem_node_t, 2>(operation, branch); |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if (details::is_string_node(branch[0])) |
| { |
| lodge_assignment(e_st_string,branch[0]); |
| |
| return synthesize_expression<assignment_string_node_t,2>(operation,branch); |
| } |
| else if (details::is_string_range_node(branch[0])) |
| { |
| lodge_assignment(e_st_string,branch[0]); |
| |
| return synthesize_expression<assignment_string_range_node_t,2>(operation,branch); |
| } |
| #endif |
| else if (details::is_vector_node(branch[0])) |
| { |
| lodge_assignment(e_st_vector,branch[0]); |
| |
| if (details::is_ivector_node(branch[1])) |
| return synthesize_expression<assignment_vecvec_node_t,2>(operation,branch); |
| else |
| return synthesize_expression<assignment_vec_node_t,2>(operation,branch); |
| } |
| else |
| { |
| parser_->set_synthesis_error("Invalid assignment operation.[1]"); |
| |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| if (details::is_variable_node(branch[0])) |
| { |
| lodge_assignment(e_st_variable,branch[0]); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (details::is_vector_elem_node(branch[0])) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_vec_elem_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (details::is_rebasevector_elem_node(branch[0])) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_rebasevec_elem_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (details::is_rebasevector_celem_node(branch[0])) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_rebasevec_celem_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (details::is_vector_node(branch[0])) |
| { |
| lodge_assignment(e_st_vector,branch[0]); |
| |
| if (details::is_ivector_node(branch[1])) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_vecvec_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::assignment_vec_op_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| case_stmt(details::e_addass,details::add_op) |
| case_stmt(details::e_subass,details::sub_op) |
| case_stmt(details::e_mulass,details::mul_op) |
| case_stmt(details::e_divass,details::div_op) |
| case_stmt(details::e_modass,details::mod_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if ( |
| (details::e_addass == operation) && |
| details::is_string_node(branch[0]) |
| ) |
| { |
| typedef details::assignment_string_node<T,details::asn_addassignment> addass_t; |
| |
| lodge_assignment(e_st_string,branch[0]); |
| |
| return synthesize_expression<addass_t,2>(operation,branch); |
| } |
| #endif |
| else |
| { |
| parser_->set_synthesis_error("Invalid assignment operation[2]"); |
| |
| return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const bool is_b0_ivec = details::is_ivector_node(branch[0]); |
| const bool is_b1_ivec = details::is_ivector_node(branch[1]); |
| |
| #define batch_eqineq_logic_case \ |
| case_stmt(details:: e_lt,details:: lt_op) \ |
| case_stmt(details:: e_lte,details:: lte_op) \ |
| case_stmt(details:: e_gt,details:: gt_op) \ |
| case_stmt(details:: e_gte,details:: gte_op) \ |
| case_stmt(details:: e_eq,details:: eq_op) \ |
| case_stmt(details:: e_ne,details:: ne_op) \ |
| case_stmt(details::e_equal,details::equal_op) \ |
| case_stmt(details:: e_and, details::and_op) \ |
| case_stmt(details:: e_nand, details::nand_op) \ |
| case_stmt(details:: e_or, details:: or_op) \ |
| case_stmt(details:: e_nor, details:: nor_op) \ |
| case_stmt(details:: e_xor, details:: xor_op) \ |
| case_stmt(details:: e_xnor, details::xnor_op) \ |
| |
| if (is_b0_ivec && is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| batch_eqineq_logic_case |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (is_b0_ivec && !is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| batch_eqineq_logic_case |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (!is_b0_ivec && is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| batch_eqineq_logic_case |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else |
| return error_node(); |
| |
| #undef batch_eqineq_logic_case |
| } |
| |
| inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const bool is_b0_ivec = details::is_ivector_node(branch[0]); |
| const bool is_b1_ivec = details::is_ivector_node(branch[1]); |
| |
| #define vector_ops \ |
| case_stmt(details::e_add,details::add_op) \ |
| case_stmt(details::e_sub,details::sub_op) \ |
| case_stmt(details::e_mul,details::mul_op) \ |
| case_stmt(details::e_div,details::div_op) \ |
| case_stmt(details::e_mod,details::mod_op) \ |
| |
| if (is_b0_ivec && is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| vector_ops |
| case_stmt(details::e_pow,details:: pow_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (is_b0_ivec && !is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| vector_ops |
| case_stmt(details::e_pow,details:: pow_op) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else if (!is_b0_ivec && is_b1_ivec) |
| { |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ |
| (operation,branch[0],branch[1]); \ |
| |
| vector_ops |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| else |
| return error_node(); |
| |
| #undef vector_ops |
| } |
| |
| inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) |
| { |
| const bool v0_is_ivar = details::is_ivariable_node(branch[0]); |
| const bool v1_is_ivar = details::is_ivariable_node(branch[1]); |
| |
| const bool v0_is_ivec = details::is_ivector_node(branch[0]); |
| const bool v1_is_ivec = details::is_ivector_node(branch[1]); |
| |
| #ifndef exprtk_disable_string_capabilities |
| const bool v0_is_str = details::is_generally_string_node(branch[0]); |
| const bool v1_is_str = details::is_generally_string_node(branch[1]); |
| #endif |
| |
| expression_node_ptr result = error_node(); |
| |
| if (v0_is_ivar && v1_is_ivar) |
| { |
| typedef details::variable_node<T>* variable_node_ptr; |
| |
| variable_node_ptr v0 = variable_node_ptr(0); |
| variable_node_ptr v1 = variable_node_ptr(0); |
| |
| if ( |
| (0 != (v0 = dynamic_cast<variable_node_ptr>(branch[0]))) && |
| (0 != (v1 = dynamic_cast<variable_node_ptr>(branch[1]))) |
| ) |
| { |
| result = node_allocator_->allocate<details::swap_node<T> >(v0,v1); |
| } |
| else |
| result = node_allocator_->allocate<details::swap_generic_node<T> >(branch[0],branch[1]); |
| } |
| else if (v0_is_ivec && v1_is_ivec) |
| { |
| result = node_allocator_->allocate<details::swap_vecvec_node<T> >(branch[0],branch[1]); |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if (v0_is_str && v1_is_str) |
| { |
| if (is_string_node(branch[0]) && is_string_node(branch[1])) |
| result = node_allocator_->allocate<details::swap_string_node<T> >(branch[0],branch[1]); |
| else |
| result = node_allocator_->allocate<details::swap_genstrings_node<T> >(branch[0],branch[1]); |
| } |
| #endif |
| else |
| { |
| parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); |
| |
| return error_node(); |
| } |
| |
| parser_->state_.activate_side_effect("synthesize_swap_expression()"); |
| |
| return result; |
| } |
| |
| #ifndef exprtk_disable_sc_andor |
| inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (details::is_constant_node(branch[0])) |
| { |
| if ( |
| (details::e_scand == operation) && |
| std::equal_to<T>()(T(0),branch[0]->value()) |
| ) |
| result = node_allocator_->allocate_c<literal_node_t>(T(0)); |
| else if ( |
| (details::e_scor == operation) && |
| std::not_equal_to<T>()(T(0),branch[0]->value()) |
| ) |
| result = node_allocator_->allocate_c<literal_node_t>(T(1)); |
| } |
| |
| if (details::is_constant_node(branch[1]) && (0 == result)) |
| { |
| if ( |
| (details::e_scand == operation) && |
| std::equal_to<T>()(T(0),branch[1]->value()) |
| ) |
| result = node_allocator_->allocate_c<literal_node_t>(T(0)); |
| else if ( |
| (details::e_scor == operation) && |
| std::not_equal_to<T>()(T(0),branch[1]->value()) |
| ) |
| result = node_allocator_->allocate_c<literal_node_t>(T(1)); |
| } |
| |
| if (result) |
| { |
| free_node(*node_allocator_,branch[0]); |
| free_node(*node_allocator_,branch[1]); |
| |
| return result; |
| } |
| else if (details::e_scand == operation) |
| return synthesize_expression<scand_node_t,2>(operation,branch); |
| else if (details::e_scor == operation) |
| return synthesize_expression<scor_node_t,2>(operation,branch); |
| else |
| return error_node(); |
| } |
| #else |
| inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) |
| { |
| return error_node(); |
| } |
| #endif |
| |
| #define basic_opr_switch_statements \ |
| case_stmt(details::e_add,details::add_op) \ |
| case_stmt(details::e_sub,details::sub_op) \ |
| case_stmt(details::e_mul,details::mul_op) \ |
| case_stmt(details::e_div,details::div_op) \ |
| case_stmt(details::e_mod,details::mod_op) \ |
| case_stmt(details::e_pow,details::pow_op) \ |
| |
| #define extended_opr_switch_statements \ |
| case_stmt(details:: e_lt,details:: lt_op) \ |
| case_stmt(details:: e_lte,details:: lte_op) \ |
| case_stmt(details:: e_gt,details:: gt_op) \ |
| case_stmt(details:: e_gte,details:: gte_op) \ |
| case_stmt(details:: e_eq,details:: eq_op) \ |
| case_stmt(details:: e_ne,details:: ne_op) \ |
| case_stmt(details:: e_and,details:: and_op) \ |
| case_stmt(details::e_nand,details::nand_op) \ |
| case_stmt(details:: e_or,details:: or_op) \ |
| case_stmt(details:: e_nor,details:: nor_op) \ |
| case_stmt(details:: e_xor,details:: xor_op) \ |
| case_stmt(details::e_xnor,details::xnor_op) \ |
| |
| #ifndef exprtk_disable_cardinal_pow_optimisation |
| template <typename TType, template <typename,typename> class IPowNode> |
| inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) |
| { |
| switch (p) |
| { |
| #define case_stmt(cp) \ |
| case cp : return node_allocator_-> \ |
| allocate<IPowNode<T,details::numeric::fast_exp<T,cp> > >(v); \ |
| |
| case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) |
| case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) |
| case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) |
| case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) |
| case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) |
| case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) |
| case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) |
| case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) |
| case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) |
| case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) |
| case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) |
| case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) |
| case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) |
| case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) |
| case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) |
| { |
| const bool not_recipricol = (c >= T(0)); |
| const int p = details::numeric::to_int32(details::numeric::abs(c)); |
| |
| if (0 == p) |
| return node_allocator_->allocate_c<literal_node_t>(T(1)); |
| else if (std::equal_to<T>()(T(2),c)) |
| { |
| return node_allocator_-> |
| template allocate_rr<typename details::vov_node<Type,details::mul_op<Type> > >(v,v); |
| } |
| else |
| { |
| if (not_recipricol) |
| return cardinal_pow_optimisation_impl<T,details::ipow_node>(v,p); |
| else |
| return cardinal_pow_optimisation_impl<T,details::ipowinv_node>(v,p); |
| } |
| } |
| |
| inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) |
| { |
| return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); |
| } |
| |
| inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) |
| { |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const bool not_recipricol = (c >= T(0)); |
| const int p = details::numeric::to_int32(details::numeric::abs(c)); |
| |
| node_allocator_->free(branch[1]); |
| |
| if (0 == p) |
| { |
| details::free_all_nodes(*node_allocator_, branch); |
| return node_allocator_->allocate_c<literal_node_t>(T(1)); |
| } |
| else if (not_recipricol) |
| return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipow_node>(branch[0],p); |
| else |
| return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipowninv_node>(branch[0],p); |
| } |
| #else |
| inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) |
| { |
| return error_node(); |
| } |
| |
| inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) |
| { |
| return false; |
| } |
| |
| inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) |
| { |
| return error_node(); |
| } |
| #endif |
| |
| struct synthesize_binary_ext_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const bool left_neg = is_neg_unary_node(branch[0]); |
| const bool right_neg = is_neg_unary_node(branch[1]); |
| |
| if (left_neg && right_neg) |
| { |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| if ( |
| !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || |
| !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) |
| ) |
| { |
| details::free_all_nodes(*expr_gen.node_allocator_,branch); |
| |
| return error_node(); |
| } |
| } |
| |
| switch (operation) |
| { |
| // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) |
| case details::e_add : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::add_op<Type> > > |
| (branch[0],branch[1])); |
| |
| // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) |
| case details::e_sub : return expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::sub_op<Type> > > |
| (branch[1],branch[0]); |
| |
| default : break; |
| } |
| } |
| else if (left_neg && !right_neg) |
| { |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) |
| { |
| details::free_all_nodes(*expr_gen.node_allocator_,branch); |
| |
| return error_node(); |
| } |
| |
| switch (operation) |
| { |
| // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) |
| case details::e_add : return expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::sub_op<Type> > > |
| (branch[1],branch[0]); |
| |
| // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) |
| case details::e_sub : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::add_op<Type> > > |
| (branch[0],branch[1])); |
| |
| // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) |
| case details::e_mul : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::mul_op<Type> > > |
| (branch[0],branch[1])); |
| |
| // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) |
| case details::e_div : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::div_op<Type> > > |
| (branch[0],branch[1])); |
| |
| default : return error_node(); |
| } |
| } |
| } |
| else if (!left_neg && right_neg) |
| { |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) |
| { |
| details::free_all_nodes(*expr_gen.node_allocator_,branch); |
| |
| return error_node(); |
| } |
| |
| switch (operation) |
| { |
| // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) |
| case details::e_add : return expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::sub_op<Type> > > |
| (branch[0],branch[1]); |
| |
| // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) |
| case details::e_sub : return expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::add_op<Type> > > |
| (branch[0],branch[1]); |
| |
| // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) |
| case details::e_mul : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::mul_op<Type> > > |
| (branch[0],branch[1])); |
| |
| // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) |
| case details::e_div : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate<typename details::binary_ext_node<Type,details::div_op<Type> > > |
| (branch[0],branch[1])); |
| |
| default : return error_node(); |
| } |
| } |
| } |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate<typename details::binary_ext_node<Type,op1<Type> > > \ |
| (branch[0],branch[1]); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_vob_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type& v = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| |
| #ifndef exprtk_disable_enhanced_features |
| if (details::is_sf3ext_node(branch[1])) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile_right<vtype>(expr_gen,v,operation,branch[1],result)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| return result; |
| } |
| } |
| #endif |
| |
| if ( |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| if (details::is_uv_node(branch[1])) |
| { |
| typedef details::uv_base_node<Type>* uvbn_ptr_t; |
| |
| details::operator_type o = static_cast<uvbn_ptr_t>(branch[1])->operation(); |
| |
| if (details::e_neg == o) |
| { |
| const Type& v1 = static_cast<uvbn_ptr_t>(branch[1])->v(); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| switch (operation) |
| { |
| case details::e_mul : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::mul_op<Type> > >(v,v1)); |
| |
| case details::e_div : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::div_op<Type> > >(v,v1)); |
| |
| default : break; |
| } |
| } |
| } |
| } |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_rc<typename details::vob_node<Type,op1<Type> > > \ |
| (v,branch[1]); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_bov_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type& v = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| |
| #ifndef exprtk_disable_enhanced_features |
| if (details::is_sf3ext_node(branch[0])) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile_left<vtype>(expr_gen,v,operation,branch[0],result)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| |
| return result; |
| } |
| } |
| #endif |
| |
| if ( |
| (details::e_add == operation) || |
| (details::e_sub == operation) || |
| (details::e_mul == operation) || |
| (details::e_div == operation) |
| ) |
| { |
| if (details::is_uv_node(branch[0])) |
| { |
| typedef details::uv_base_node<Type>* uvbn_ptr_t; |
| |
| details::operator_type o = static_cast<uvbn_ptr_t>(branch[0])->operation(); |
| |
| if (details::e_neg == o) |
| { |
| const Type& v0 = static_cast<uvbn_ptr_t>(branch[0])->v(); |
| |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| |
| switch (operation) |
| { |
| case details::e_add : return expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::sub_op<Type> > >(v,v0); |
| |
| case details::e_sub : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::add_op<Type> > >(v0,v)); |
| |
| case details::e_mul : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::mul_op<Type> > >(v0,v)); |
| |
| case details::e_div : return expr_gen(details::e_neg, |
| expr_gen.node_allocator_-> |
| template allocate_rr<typename details:: |
| vov_node<Type,details::div_op<Type> > >(v0,v)); |
| default : break; |
| } |
| } |
| } |
| } |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_cr<typename details::bov_node<Type,op1<Type> > > \ |
| (branch[0],v); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_cob_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| |
| if ((T(0) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_div == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[1]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_add == operation)) |
| return branch[1]; |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| return branch[1]; |
| |
| if (details::is_cob_node(branch[1])) |
| { |
| // Simplify expressions of the form: |
| // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) |
| // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x |
| if ( |
| (operation == details::e_mul) || |
| (operation == details::e_add) |
| ) |
| { |
| details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); |
| |
| if (operation == cobnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_add : cobnode->set_c(c + cobnode->c()); break; |
| case details::e_mul : cobnode->set_c(c * cobnode->c()); break; |
| default : return error_node(); |
| } |
| |
| return cobnode; |
| } |
| } |
| |
| if (operation == details::e_mul) |
| { |
| details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); |
| details::operator_type cob_opr = cobnode->operation(); |
| |
| if ( |
| (details::e_div == cob_opr) || |
| (details::e_mul == cob_opr) |
| ) |
| { |
| switch (cob_opr) |
| { |
| case details::e_div : cobnode->set_c(c * cobnode->c()); break; |
| case details::e_mul : cobnode->set_c(cobnode->c() / c); break; |
| default : return error_node(); |
| } |
| |
| return cobnode; |
| } |
| } |
| else if (operation == details::e_div) |
| { |
| details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); |
| details::operator_type cob_opr = cobnode->operation(); |
| |
| if ( |
| (details::e_div == cob_opr) || |
| (details::e_mul == cob_opr) |
| ) |
| { |
| details::expression_node<Type>* new_cobnode = error_node(); |
| |
| switch (cob_opr) |
| { |
| case details::e_div : new_cobnode = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > > |
| (c / cobnode->c(),cobnode->move_branch(0)); |
| break; |
| |
| case details::e_mul : new_cobnode = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > |
| (c / cobnode->c(),cobnode->move_branch(0)); |
| break; |
| |
| default : return error_node(); |
| } |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return new_cobnode; |
| } |
| } |
| } |
| #ifndef exprtk_disable_enhanced_features |
| else if (details::is_sf3ext_node(branch[1])) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile_right<ctype>(expr_gen,c,operation,branch[1],result)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return result; |
| } |
| } |
| #endif |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_tt<typename details::cob_node<Type,op1<Type> > > \ |
| (c,branch[1]); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_boc_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| if ((T(0) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_div == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[0]); |
| |
| return expr_gen(std::numeric_limits<T>::quiet_NaN()); |
| } |
| else if ((T(0) == c) && (details::e_add == operation)) |
| return branch[0]; |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| return branch[0]; |
| |
| if (details::is_boc_node(branch[0])) |
| { |
| // Simplify expressions of the form: |
| // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 |
| // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 |
| if ( |
| (operation == details::e_mul) || |
| (operation == details::e_add) |
| ) |
| { |
| details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); |
| |
| if (operation == bocnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_add : bocnode->set_c(c + bocnode->c()); break; |
| case details::e_mul : bocnode->set_c(c * bocnode->c()); break; |
| default : return error_node(); |
| } |
| |
| return bocnode; |
| } |
| } |
| else if (operation == details::e_div) |
| { |
| details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); |
| details::operator_type boc_opr = bocnode->operation(); |
| |
| if ( |
| (details::e_div == boc_opr) || |
| (details::e_mul == boc_opr) |
| ) |
| { |
| switch (boc_opr) |
| { |
| case details::e_div : bocnode->set_c(c * bocnode->c()); break; |
| case details::e_mul : bocnode->set_c(bocnode->c() / c); break; |
| default : return error_node(); |
| } |
| |
| return bocnode; |
| } |
| } |
| else if (operation == details::e_pow) |
| { |
| // (v ^ c0) ^ c1 --> v ^(c0 * c1) |
| details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); |
| details::operator_type boc_opr = bocnode->operation(); |
| |
| if (details::e_pow == boc_opr) |
| { |
| bocnode->set_c(bocnode->c() * c); |
| |
| return bocnode; |
| } |
| } |
| } |
| |
| #ifndef exprtk_disable_enhanced_features |
| if (details::is_sf3ext_node(branch[0])) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile_left<ctype>(expr_gen,c,operation,branch[0],result)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| |
| return result; |
| } |
| } |
| #endif |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_cr<typename details::boc_node<Type,op1<Type> > > \ |
| (branch[0],c); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_cocob_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| expression_node_ptr result = error_node(); |
| |
| // (cob) o c --> cob |
| if (details::is_cob_node(branch[0])) |
| { |
| details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[0]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| |
| if ((T(0) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_div == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return expr_gen(T(std::numeric_limits<T>::quiet_NaN())); |
| } |
| else if ((T(0) == c) && (details::e_add == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[1]); |
| return branch[0]; |
| } |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[1]); |
| return branch[0]; |
| } |
| else if ((T(1) == c) && (details::e_div == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[1]); |
| return branch[0]; |
| } |
| |
| bool op_addsub = (details::e_add == cobnode->operation()) || |
| (details::e_sub == cobnode->operation()); |
| |
| if (op_addsub) |
| { |
| switch (operation) |
| { |
| case details::e_add : cobnode->set_c(cobnode->c() + c); break; |
| case details::e_sub : cobnode->set_c(cobnode->c() - c); break; |
| default : return error_node(); |
| } |
| |
| result = cobnode; |
| } |
| else if (details::e_mul == cobnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_mul : cobnode->set_c(cobnode->c() * c); break; |
| case details::e_div : cobnode->set_c(cobnode->c() / c); break; |
| default : return error_node(); |
| } |
| |
| result = cobnode; |
| } |
| else if (details::e_div == cobnode->operation()) |
| { |
| if (details::e_mul == operation) |
| { |
| cobnode->set_c(cobnode->c() * c); |
| result = cobnode; |
| } |
| else if (details::e_div == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > |
| (cobnode->c() / c,cobnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| } |
| } |
| |
| if (result) |
| { |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| |
| // c o (cob) --> cob |
| else if (details::is_cob_node(branch[1])) |
| { |
| details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| |
| if ((T(0) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_div == operation)) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| |
| return expr_gen(T(0)); |
| } |
| else if ((T(0) == c) && (details::e_add == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[0]); |
| return branch[1]; |
| } |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| { |
| free_node(*expr_gen.node_allocator_, branch[0]); |
| return branch[1]; |
| } |
| |
| if (details::e_add == cobnode->operation()) |
| { |
| if (details::e_add == operation) |
| { |
| cobnode->set_c(c + cobnode->c()); |
| result = cobnode; |
| } |
| else if (details::e_sub == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > |
| (c - cobnode->c(),cobnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_sub == cobnode->operation()) |
| { |
| if (details::e_add == operation) |
| { |
| cobnode->set_c(c + cobnode->c()); |
| result = cobnode; |
| } |
| else if (details::e_sub == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::add_op<Type> > > |
| (c - cobnode->c(),cobnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_mul == cobnode->operation()) |
| { |
| if (details::e_mul == operation) |
| { |
| cobnode->set_c(c * cobnode->c()); |
| result = cobnode; |
| } |
| else if (details::e_div == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > |
| (c / cobnode->c(),cobnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_div == cobnode->operation()) |
| { |
| if (details::e_mul == operation) |
| { |
| cobnode->set_c(c * cobnode->c()); |
| result = cobnode; |
| } |
| else if (details::e_div == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > > |
| (c / cobnode->c(),cobnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| |
| if (result) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| } |
| } |
| |
| return result; |
| } |
| }; |
| |
| struct synthesize_coboc_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| expression_node_ptr result = error_node(); |
| |
| // (boc) o c --> boc |
| if (details::is_boc_node(branch[0])) |
| { |
| details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| |
| if (details::e_add == bocnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_add : bocnode->set_c(bocnode->c() + c); break; |
| case details::e_sub : bocnode->set_c(bocnode->c() - c); break; |
| default : return error_node(); |
| } |
| |
| result = bocnode; |
| } |
| else if (details::e_mul == bocnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_mul : bocnode->set_c(bocnode->c() * c); break; |
| case details::e_div : bocnode->set_c(bocnode->c() / c); break; |
| default : return error_node(); |
| } |
| |
| result = bocnode; |
| } |
| else if (details::e_sub == bocnode->operation()) |
| { |
| if (details::e_add == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > |
| (bocnode->move_branch(0),c - bocnode->c()); |
| |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| } |
| else if (details::e_sub == operation) |
| { |
| bocnode->set_c(bocnode->c() + c); |
| result = bocnode; |
| } |
| } |
| else if (details::e_div == bocnode->operation()) |
| { |
| switch (operation) |
| { |
| case details::e_div : bocnode->set_c(bocnode->c() * c); break; |
| case details::e_mul : bocnode->set_c(bocnode->c() / c); break; |
| default : return error_node(); |
| } |
| |
| result = bocnode; |
| } |
| |
| if (result) |
| { |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| |
| // c o (boc) --> boc |
| else if (details::is_boc_node(branch[1])) |
| { |
| details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[1]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| |
| if (details::e_add == bocnode->operation()) |
| { |
| if (details::e_add == operation) |
| { |
| bocnode->set_c(c + bocnode->c()); |
| result = bocnode; |
| } |
| else if (details::e_sub == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > |
| (c - bocnode->c(),bocnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_sub == bocnode->operation()) |
| { |
| if (details::e_add == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > |
| (bocnode->move_branch(0),c - bocnode->c()); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| else if (details::e_sub == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > |
| (c + bocnode->c(),bocnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_mul == bocnode->operation()) |
| { |
| if (details::e_mul == operation) |
| { |
| bocnode->set_c(c * bocnode->c()); |
| result = bocnode; |
| } |
| else if (details::e_div == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > |
| (c / bocnode->c(),bocnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| else if (details::e_div == bocnode->operation()) |
| { |
| if (details::e_mul == operation) |
| { |
| bocnode->set_c(bocnode->c() / c); |
| result = bocnode; |
| } |
| else if (details::e_div == operation) |
| { |
| result = expr_gen.node_allocator_-> |
| template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > |
| (c * bocnode->c(),bocnode->move_branch(0)); |
| |
| free_node(*expr_gen.node_allocator_,branch[1]); |
| } |
| } |
| |
| if (result) |
| { |
| free_node(*expr_gen.node_allocator_,branch[0]); |
| } |
| } |
| |
| return result; |
| } |
| }; |
| |
| #ifndef exprtk_disable_enhanced_features |
| inline bool synthesize_expression(const details::operator_type& operation, |
| expression_node_ptr (&branch)[2], |
| expression_node_ptr& result) |
| { |
| result = error_node(); |
| |
| if (!operation_optimisable(operation)) |
| return false; |
| |
| const std::string node_id = branch_to_id(branch); |
| typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); |
| |
| if (synthesize_map_.end() != itr) |
| { |
| result = itr->second(*this,operation,branch); |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| struct synthesize_vov_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_rr<typename details::vov_node<Type,op1<Type> > > \ |
| (v1,v2); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_cov_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type c = static_cast<details::literal_node<Type>*> (branch[0])->value(); |
| const Type& v = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| if ((T(0) == c) && (details::e_mul == operation)) |
| return expr_gen(T(0)); |
| else if ((T(0) == c) && (details::e_div == operation)) |
| return expr_gen(T(0)); |
| else if ((T(0) == c) && (details::e_add == operation)) |
| return static_cast<details::variable_node<Type>*>(branch[1]); |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| return static_cast<details::variable_node<Type>*>(branch[1]); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_cr<typename details::cov_node<Type,op1<Type> > > \ |
| (c,v); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_voc_expression |
| { |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| const Type& v = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c = static_cast<details::literal_node<Type>*> (branch[1])->value(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| if (expr_gen.cardinal_pow_optimisable(operation,c)) |
| { |
| if (std::equal_to<T>()(T(1),c)) |
| return branch[0]; |
| else |
| return expr_gen.cardinal_pow_optimisation(v,c); |
| } |
| else if ((T(0) == c) && (details::e_mul == operation)) |
| return expr_gen(T(0)); |
| else if ((T(0) == c) && (details::e_div == operation)) |
| return expr_gen(std::numeric_limits<T>::quiet_NaN()); |
| else if ((T(0) == c) && (details::e_add == operation)) |
| return static_cast<details::variable_node<Type>*>(branch[0]); |
| else if ((T(1) == c) && (details::e_mul == operation)) |
| return static_cast<details::variable_node<Type>*>(branch[0]); |
| else if ((T(1) == c) && (details::e_div == operation)) |
| return static_cast<details::variable_node<Type>*>(branch[0]); |
| |
| switch (operation) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return expr_gen.node_allocator_-> \ |
| template allocate_rc<typename details::voc_node<Type,op1<Type> > > \ |
| (v,c); \ |
| |
| basic_opr_switch_statements |
| extended_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| }; |
| |
| struct synthesize_sf3ext_expression |
| { |
| template <typename T0, typename T1, typename T2> |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& sf3opr, |
| T0 t0, T1 t1, T2 t2) |
| { |
| switch (sf3opr) |
| { |
| #define case_stmt(op) \ |
| case details::e_sf##op : return details::T0oT1oT2_sf3ext<T,T0,T1,T2,details::sf##op##_op<Type> >:: \ |
| allocate(*(expr_gen.node_allocator_),t0,t1,t2); \ |
| |
| case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) |
| case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) |
| case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) |
| case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) |
| case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) |
| case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) |
| case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) |
| case_stmt(28) case_stmt(29) case_stmt(30) |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename T0, typename T1, typename T2> |
| static inline bool compile(expression_generator<Type>& expr_gen, const std::string& id, |
| T0 t0, T1 t1, T2 t2, |
| expression_node_ptr& result) |
| { |
| details::operator_type sf3opr; |
| |
| if (!expr_gen.sf3_optimisable(id,sf3opr)) |
| return false; |
| else |
| result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2); |
| |
| return true; |
| } |
| }; |
| |
| struct synthesize_sf4ext_expression |
| { |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& sf4opr, |
| T0 t0, T1 t1, T2 t2, T3 t3) |
| { |
| switch (sf4opr) |
| { |
| #define case_stmt0(op) \ |
| case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sf##op##_op<Type> >:: \ |
| allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ |
| |
| |
| #define case_stmt1(op) \ |
| case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sfext##op##_op<Type> >:: \ |
| allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ |
| |
| case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) |
| case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) |
| case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) |
| case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) |
| case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) |
| case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) |
| case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) |
| case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) |
| case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) |
| |
| case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) |
| case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) |
| case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) |
| case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) |
| case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) |
| case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) |
| case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) |
| case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) |
| case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) |
| case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) |
| case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) |
| case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) |
| case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) |
| case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) |
| case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) |
| case_stmt1(60) |
| |
| #undef case_stmt0 |
| #undef case_stmt1 |
| default : return error_node(); |
| } |
| } |
| |
| template <typename T0, typename T1, typename T2, typename T3> |
| static inline bool compile(expression_generator<Type>& expr_gen, const std::string& id, |
| T0 t0, T1 t1, T2 t2, T3 t3, |
| expression_node_ptr& result) |
| { |
| details::operator_type sf4opr; |
| |
| if (!expr_gen.sf4_optimisable(id,sf4opr)) |
| return false; |
| else |
| result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3); |
| |
| return true; |
| } |
| |
| // T o (sf3ext) |
| template <typename ExternalType> |
| static inline bool compile_right(expression_generator<Type>& expr_gen, |
| ExternalType t, |
| const details::operator_type& operation, |
| expression_node_ptr& sf3node, |
| expression_node_ptr& result) |
| { |
| if (!details::is_sf3ext_node(sf3node)) |
| return false; |
| |
| typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr; |
| |
| sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node); |
| std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; |
| |
| switch (n->type()) |
| { |
| case details::expression_node<Type>::e_covoc : return compile_right_impl |
| <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_covov : return compile_right_impl |
| <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vocov : return compile_right_impl |
| <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vovoc : return compile_right_impl |
| <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vovov : return compile_right_impl |
| <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| default : return false; |
| } |
| } |
| |
| // (sf3ext) o T |
| template <typename ExternalType> |
| static inline bool compile_left(expression_generator<Type>& expr_gen, |
| ExternalType t, |
| const details::operator_type& operation, |
| expression_node_ptr& sf3node, |
| expression_node_ptr& result) |
| { |
| if (!details::is_sf3ext_node(sf3node)) |
| return false; |
| |
| typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr; |
| |
| sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node); |
| std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; |
| |
| switch (n->type()) |
| { |
| case details::expression_node<Type>::e_covoc : return compile_left_impl |
| <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_covov : return compile_left_impl |
| <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vocov : return compile_left_impl |
| <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vovoc : return compile_left_impl |
| <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype> |
| (expr_gen,id,t,sf3node,result); |
| |
| case details::expression_node<Type>::e_vovov : return compile_left_impl |
| <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype> |
| (expr_gen,id,t,sf3node,result); |
| |
| default : return false; |
| } |
| } |
| |
| template <typename SF3TypeNode, typename ExternalType, typename T0, typename T1, typename T2> |
| static inline bool compile_right_impl(expression_generator<Type>& expr_gen, |
| const std::string& id, |
| ExternalType t, |
| expression_node_ptr& node, |
| expression_node_ptr& result) |
| { |
| SF3TypeNode* n = dynamic_cast<SF3TypeNode*>(node); |
| |
| if (n) |
| { |
| T0 t0 = n->t0(); |
| T1 t1 = n->t1(); |
| T2 t2 = n->t2(); |
| |
| return synthesize_sf4ext_expression:: |
| template compile<ExternalType,T0,T1,T2>(expr_gen,id,t,t0,t1,t2,result); |
| } |
| else |
| return false; |
| } |
| |
| template <typename SF3TypeNode, typename ExternalType, typename T0, typename T1, typename T2> |
| static inline bool compile_left_impl(expression_generator<Type>& expr_gen, |
| const std::string& id, |
| ExternalType t, |
| expression_node_ptr& node, |
| expression_node_ptr& result) |
| { |
| SF3TypeNode* n = dynamic_cast<SF3TypeNode*>(node); |
| |
| if (n) |
| { |
| T0 t0 = n->t0(); |
| T1 t1 = n->t1(); |
| T2 t2 = n->t2(); |
| |
| return synthesize_sf4ext_expression:: |
| template compile<T0,T1,T2,ExternalType>(expr_gen,id,t0,t1,t2,t,result); |
| } |
| else |
| return false; |
| } |
| }; |
| |
| struct synthesize_vovov_expression0 |
| { |
| typedef typename vovov_t::type0 node_type; |
| typedef typename vovov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 v1) o1 (v2) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]); |
| const Type& v0 = vov->v0(); |
| const Type& v1 = vov->v1(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = vov->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,vtype>(expr_gen,"t/(t*t)",v0,v1,v2,result); |
| |
| exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovov_expression1 |
| { |
| typedef typename vovov_t::type1 node_type; |
| typedef typename vovov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0) o0 (v1 o1 v2) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vov->v0(); |
| const Type& v2 = vov->v1(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = vov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,vtype>(expr_gen,"(t*t)/t",v0,v2,v1,result); |
| |
| exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovoc_expression0 |
| { |
| typedef typename vovoc_t::type0 node_type; |
| typedef typename vovoc_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 v1) o1 (c) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]); |
| const Type& v0 = vov->v0(); |
| const Type& v1 = vov->v1(); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = vov->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); |
| |
| exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovoc_expression1 |
| { |
| typedef typename vovoc_t::type1 node_type; |
| typedef typename vovoc_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0) o0 (v1 o1 c) |
| const details::voc_base_node<Type>* voc = static_cast<const details::voc_base_node<Type>*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = voc->v(); |
| const Type c = voc->c(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = voc->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,ctype,vtype>(expr_gen,"(t*t)/t",v0,c,v1,result); |
| |
| exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vocov_expression0 |
| { |
| typedef typename vocov_t::type0 node_type; |
| typedef typename vocov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 c) o1 (v1) |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]); |
| const Type& v0 = voc->v(); |
| const Type c = voc->c(); |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = voc->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); |
| |
| exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_vocov_expression1 |
| { |
| typedef typename vocov_t::type1 node_type; |
| typedef typename vocov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0) o0 (c o1 v1) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c = cov->c(); |
| const Type& v1 = cov->v(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = cov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // v0 / (c / v1) --> (vovoc) (v0 * v1) / c |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,"(t*t)/t",v0,v1,c,result); |
| |
| exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covov_expression0 |
| { |
| typedef typename covov_t::type0 node_type; |
| typedef typename covov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c o0 v0) o1 (v1) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]); |
| const Type c = cov->c(); |
| const Type& v0 = cov->v(); |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = cov->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c / v0) / v1 --> (covov) c / (v0 * v1) |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",c,v0,v1,result); |
| |
| exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_covov_expression1 |
| { |
| typedef typename covov_t::type1 node_type; |
| typedef typename covov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c) o0 (v0 o1 v1) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vov->v0(); |
| const Type& v1 = vov->v1(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = vov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // c / (v0 / v1) --> (covov) (c * v1) / v0 |
| if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",c,v1,v0,result); |
| |
| exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covoc_expression0 |
| { |
| typedef typename covoc_t::type0 node_type; |
| typedef typename covoc_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c0 o0 v) o1 (c1) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]); |
| const Type c0 = cov->c(); |
| const Type& v = cov->v(); |
| const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = cov->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c0 + v) + c1 --> (cov) (c0 + c1) + v |
| if ((details::e_add == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); |
| } |
| // (c0 + v) - c1 --> (cov) (c0 - c1) + v |
| else if ((details::e_add == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); |
| } |
| // (c0 - v) + c1 --> (cov) (c0 + c1) - v |
| else if ((details::e_sub == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); |
| } |
| // (c0 - v) - c1 --> (cov) (c0 - c1) - v |
| else if ((details::e_sub == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); |
| } |
| // (c0 * v) * c1 --> (cov) (c0 * c1) * v |
| else if ((details::e_mul == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); |
| } |
| // (c0 * v) / c1 --> (cov) (c0 / c1) * v |
| else if ((details::e_mul == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); |
| } |
| // (c0 / v) * c1 --> (cov) (c0 * c1) / v |
| else if ((details::e_div == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); |
| } |
| // (c0 / v) / c1 --> (cov) (c0 / c1) / v |
| else if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_covoc_expression1 |
| { |
| typedef typename covoc_t::type1 node_type; |
| typedef typename covoc_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c0) o0 (v o1 c1) |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v = voc->v(); |
| const Type c1 = voc->c(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = voc->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c0) + (v + c1) --> (cov) (c0 + c1) + v |
| if ((details::e_add == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); |
| } |
| // (c0) + (v - c1) --> (cov) (c0 - c1) + v |
| else if ((details::e_add == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); |
| } |
| // (c0) - (v + c1) --> (cov) (c0 - c1) - v |
| else if ((details::e_sub == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); |
| } |
| // (c0) - (v - c1) --> (cov) (c0 + c1) - v |
| else if ((details::e_sub == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); |
| } |
| // (c0) * (v * c1) --> (voc) v * (c0 * c1) |
| else if ((details::e_mul == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); |
| } |
| // (c0) * (v / c1) --> (cov) (c0 / c1) * v |
| else if ((details::e_mul == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); |
| } |
| // (c0) / (v * c1) --> (cov) (c0 / c1) / v |
| else if ((details::e_div == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); |
| } |
| // (c0) / (v / c1) --> (cov) (c0 * c1) / v |
| else if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_cocov_expression0 |
| { |
| typedef typename cocov_t::type0 node_type; |
| static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) |
| { |
| // (c0 o0 c1) o1 (v) - Not possible. |
| return error_node(); |
| } |
| }; |
| |
| struct synthesize_cocov_expression1 |
| { |
| typedef typename cocov_t::type1 node_type; |
| typedef typename cocov_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c0) o0 (c1 o1 v) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type c1 = cov->c(); |
| const Type& v = cov->v(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = cov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c0) + (c1 + v) --> (cov) (c0 + c1) + v |
| if ((details::e_add == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); |
| } |
| // (c0) + (c1 - v) --> (cov) (c0 + c1) - v |
| else if ((details::e_add == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); |
| } |
| // (c0) - (c1 + v) --> (cov) (c0 - c1) - v |
| else if ((details::e_sub == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); |
| } |
| // (c0) - (c1 - v) --> (cov) (c0 - c1) + v |
| else if ((details::e_sub == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); |
| } |
| // (c0) * (c1 * v) --> (cov) (c0 * c1) * v |
| else if ((details::e_mul == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); |
| } |
| // (c0) * (c1 / v) --> (cov) (c0 * c1) / v |
| else if ((details::e_mul == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); |
| } |
| // (c0) / (c1 * v) --> (cov) (c0 / c1) / v |
| else if ((details::e_div == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); |
| } |
| // (c0) / (c1 / v) --> (cov) (c0 / c1) * v |
| else if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<ctype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,c1,v,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vococ_expression0 |
| { |
| typedef typename vococ_t::type0 node_type; |
| typedef typename vococ_t::sf3_type sf3_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v o0 c0) o1 (c1) |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]); |
| const Type& v = voc->v(); |
| const Type& c0 = voc->c(); |
| const Type& c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = voc->operation(); |
| const details::operator_type o1 = operation; |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v + c0) + c1 --> (voc) v + (c0 + c1) |
| if ((details::e_add == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c0 + c1); |
| } |
| // (v + c0) - c1 --> (voc) v + (c0 - c1) |
| else if ((details::e_add == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c0 - c1); |
| } |
| // (v - c0) + c1 --> (voc) v - (c0 + c1) |
| else if ((details::e_sub == o0) && (details::e_add == o1)) |
| { |
| exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c1 - c0); |
| } |
| // (v - c0) - c1 --> (voc) v - (c0 + c1) |
| else if ((details::e_sub == o0) && (details::e_sub == o1)) |
| { |
| exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::sub_op<Type> > >(v,c0 + c1); |
| } |
| // (v * c0) * c1 --> (voc) v * (c0 * c1) |
| else if ((details::e_mul == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c0 * c1); |
| } |
| // (v * c0) / c1 --> (voc) v * (c0 / c1) |
| else if ((details::e_mul == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c0 / c1); |
| } |
| // (v / c0) * c1 --> (voc) v * (c1 / c0) |
| else if ((details::e_div == o0) && (details::e_mul == o1)) |
| { |
| exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c1 / c0); |
| } |
| // (v / c0) / c1 --> (voc) v / (c0 * c1) |
| else if ((details::e_div == o0) && (details::e_div == o1)) |
| { |
| exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1); |
| } |
| // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) |
| else if ((details::e_pow == o0) && (details::e_pow == o1)) |
| { |
| exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); |
| |
| return expr_gen.node_allocator_-> |
| template allocate_rc<typename details::voc_node<Type,details::pow_op<Type> > >(v,c0 * c1); |
| } |
| } |
| |
| if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v,c0,c1,f0,f1); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, const details::operator_type o1) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); |
| } |
| }; |
| |
| struct synthesize_vococ_expression1 |
| { |
| typedef typename vococ_t::type0 node_type; |
| |
| static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) |
| { |
| // (v) o0 (c0 o1 c1) - Not possible. |
| exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); |
| return error_node(); |
| } |
| }; |
| |
| struct synthesize_vovovov_expression0 |
| { |
| typedef typename vovovov_t::type0 node_type; |
| typedef typename vovovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 v1) o1 (v2 o2 v3) |
| const details::vov_base_node<Type>* vov0 = static_cast<details::vov_base_node<Type>*>(branch[0]); |
| const details::vov_base_node<Type>* vov1 = static_cast<details::vov_base_node<Type>*>(branch[1]); |
| const Type& v0 = vov0->v0(); |
| const Type& v1 = vov0->v1(); |
| const Type& v2 = vov1->v0(); |
| const Type& v3 = vov1->v1(); |
| const details::operator_type o0 = vov0->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = vov1->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) |
| if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result); |
| |
| exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result); |
| |
| exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) |
| else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t+t)*(t/t)",v0,v1,v3,v2,result); |
| |
| exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) |
| else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t-t)*(t/t)",v0,v1,v3,v2,result); |
| |
| exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,vtype>(expr_gen,"((t*t)*t)/t",v0,v1,v3,v2,result); |
| |
| exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovovoc_expression0 |
| { |
| typedef typename vovovoc_t::type0 node_type; |
| typedef typename vovovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 v1) o1 (v2 o2 c) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]); |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[1]); |
| const Type& v0 = vov->v0(); |
| const Type& v1 = vov->v1(); |
| const Type& v2 = voc->v (); |
| const Type c = voc->c (); |
| const details::operator_type o0 = vov->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = voc->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) |
| if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,ctype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); |
| |
| exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) |
| if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,ctype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); |
| |
| exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovocov_expression0 |
| { |
| typedef typename vovocov_t::type0 node_type; |
| typedef typename vovocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 v1) o1 (c o2 v2) |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]); |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]); |
| const Type& v0 = vov->v0(); |
| const Type& v1 = vov->v1(); |
| const Type& v2 = cov->v (); |
| const Type c = cov->c (); |
| const details::operator_type o0 = vov->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = cov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) |
| if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,ctype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); |
| |
| exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) |
| if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,vtype,ctype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); |
| |
| exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vocovov_expression0 |
| { |
| typedef typename vocovov_t::type0 node_type; |
| typedef typename vocovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 c) o1 (v1 o2 v2) |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]); |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]); |
| const Type c = voc->c (); |
| const Type& v0 = voc->v (); |
| const Type& v1 = vov->v0(); |
| const Type& v2 = vov->v1(); |
| const details::operator_type o0 = voc->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = vov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) |
| if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,ctype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v1,c,v2,result); |
| |
| exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) |
| if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,vtype,ctype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v2,c,v1,result); |
| |
| exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covovov_expression0 |
| { |
| typedef typename covovov_t::type0 node_type; |
| typedef typename covovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c o0 v0) o1 (v1 o2 v2) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]); |
| const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]); |
| const Type c = cov->c (); |
| const Type& v0 = cov->v (); |
| const Type& v1 = vov->v0(); |
| const Type& v2 = vov->v1(); |
| const details::operator_type o0 = cov->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = vov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) |
| if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<ctype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",c,v1,v0,v2,result); |
| |
| exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) |
| if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<ctype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",c,v2,v0,v1,result); |
| |
| exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covocov_expression0 |
| { |
| typedef typename covocov_t::type0 node_type; |
| typedef typename covocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c0 o0 v0) o1 (c1 o2 v1) |
| const details::cov_base_node<Type>* cov0 = static_cast<details::cov_base_node<Type>*>(branch[0]); |
| const details::cov_base_node<Type>* cov1 = static_cast<details::cov_base_node<Type>*>(branch[1]); |
| const Type c0 = cov0->c(); |
| const Type& v0 = cov0->v(); |
| const Type c1 = cov1->c(); |
| const Type& v1 = cov1->v(); |
| const details::operator_type o0 = cov0->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = cov1->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 |
| if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 |
| else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 |
| else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 |
| else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v1,v0,result); |
| |
| exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) |
| else if ( |
| (std::equal_to<T>()(c0,c1)) && |
| (details::e_mul == o0) && |
| (details::e_mul == o2) && |
| ( |
| (details::e_add == o1) || |
| (details::e_sub == o1) |
| ) |
| ) |
| { |
| std::string specfunc; |
| |
| switch (o1) |
| { |
| case details::e_add : specfunc = "t*(t+t)"; break; |
| case details::e_sub : specfunc = "t*(t-t)"; break; |
| default : return error_node(); |
| } |
| |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); |
| |
| exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vocovoc_expression0 |
| { |
| typedef typename vocovoc_t::type0 node_type; |
| typedef typename vocovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 c0) o1 (v1 o2 c1) |
| const details::voc_base_node<Type>* voc0 = static_cast<details::voc_base_node<Type>*>(branch[0]); |
| const details::voc_base_node<Type>* voc1 = static_cast<details::voc_base_node<Type>*>(branch[1]); |
| const Type c0 = voc0->c(); |
| const Type& v0 = voc0->v(); |
| const Type c1 = voc1->c(); |
| const Type& v1 = voc1->v(); |
| const details::operator_type o0 = voc0->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = voc1->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 |
| if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 |
| else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 |
| else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); |
| |
| exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 |
| else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); |
| |
| exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,ctype,vtype,ctype>(expr_gen,"(t*t)*(t+t)",v0,T(1) / c0,v1,c1,result); |
| |
| exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf4ext_expression:: |
| template compile<vtype,ctype,vtype,ctype>(expr_gen,"(t*t)*(t-t)",v0,T(1) / c0,v1,c1,result); |
| |
| exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) |
| else if ( |
| (std::equal_to<T>()(c0,c1)) && |
| (details::e_mul == o0) && |
| (details::e_mul == o2) && |
| ( |
| (details::e_add == o1) || |
| (details::e_sub == o1) |
| ) |
| ) |
| { |
| std::string specfunc; |
| |
| switch (o1) |
| { |
| case details::e_add : specfunc = "t*(t+t)"; break; |
| case details::e_sub : specfunc = "t*(t-t)"; break; |
| default : return error_node(); |
| } |
| |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); |
| |
| exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c |
| else if ( |
| (std::equal_to<T>()(c0,c1)) && |
| (details::e_div == o0) && |
| (details::e_div == o2) && |
| ( |
| (details::e_add == o1) || |
| (details::e_sub == o1) |
| ) |
| ) |
| { |
| std::string specfunc; |
| |
| switch (o1) |
| { |
| case details::e_add : specfunc = "(t+t)/t"; break; |
| case details::e_sub : specfunc = "(t-t)/t"; break; |
| default : return error_node(); |
| } |
| |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,specfunc,v0,v1,c0,result); |
| |
| exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covovoc_expression0 |
| { |
| typedef typename covovoc_t::type0 node_type; |
| typedef typename covovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (c0 o0 v0) o1 (v1 o2 c1) |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]); |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[1]); |
| const Type c0 = cov->c(); |
| const Type& v0 = cov->v(); |
| const Type c1 = voc->c(); |
| const Type& v1 = voc->v(); |
| const details::operator_type o0 = cov->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = voc->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 |
| if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 |
| else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 |
| else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 |
| else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); |
| |
| exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) |
| else if ( |
| (std::equal_to<T>()(c0,c1)) && |
| (details::e_mul == o0) && |
| (details::e_mul == o2) && |
| ( |
| (details::e_add == o1) || |
| (details::e_sub == o1) |
| ) |
| ) |
| { |
| std::string specfunc; |
| |
| switch (o1) |
| { |
| case details::e_add : specfunc = "t*(t+t)"; break; |
| case details::e_sub : specfunc = "t*(t-t)"; break; |
| default : return error_node(); |
| } |
| |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); |
| |
| exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vococov_expression0 |
| { |
| typedef typename vococov_t::type0 node_type; |
| typedef typename vococov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 c0) o1 (c1 o2 v1) |
| const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]); |
| const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]); |
| const Type c0 = voc->c(); |
| const Type& v0 = voc->v(); |
| const Type c1 = cov->c(); |
| const Type& v1 = cov->v(); |
| const details::operator_type o0 = voc->operation(); |
| const details::operator_type o1 = operation; |
| const details::operator_type o2 = cov->operation(); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (expr_gen.parser_->settings_.strength_reduction_enabled()) |
| { |
| // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 |
| if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 |
| else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) |
| else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); |
| |
| exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 |
| else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) |
| else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); |
| |
| exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) |
| else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); |
| |
| exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) |
| else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) |
| { |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<vtype,vtype,ctype>(expr_gen,"(t*t)*t",v0,v1,Type(1) / (c0 * c1),result); |
| |
| exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) |
| else if ( |
| (std::equal_to<T>()(c0,c1)) && |
| (details::e_mul == o0) && |
| (details::e_mul == o2) && |
| ( |
| (details::e_add == o1) || (details::e_sub == o1) |
| ) |
| ) |
| { |
| std::string specfunc; |
| |
| switch (o1) |
| { |
| case details::e_add : specfunc = "t*(t+t)"; break; |
| case details::e_sub : specfunc = "t*(t-t)"; break; |
| default : return error_node(); |
| } |
| |
| const bool synthesis_result = |
| synthesize_sf3ext_expression:: |
| template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); |
| |
| exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); |
| |
| return (synthesis_result) ? result : error_node(); |
| } |
| } |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o1,f1)) |
| return error_node(); |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| else |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovovov_expression1 |
| { |
| typedef typename vovovov_t::type1 node_type; |
| typedef typename vovovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (v1 o1 (v2 o2 v3)) |
| typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vovov->t0(); |
| const Type& v2 = vovov->t1(); |
| const Type& v3 = vovov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovov->f0(); |
| binary_functor_t f2 = vovov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vovovoc_expression1 |
| { |
| typedef typename vovovoc_t::type1 node_type; |
| typedef typename vovovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (v1 o1 (v2 o2 c)) |
| typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vovoc->t0(); |
| const Type& v2 = vovoc->t1(); |
| const Type c = vovoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovoc->f0(); |
| binary_functor_t f2 = vovoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vovocov_expression1 |
| { |
| typedef typename vovocov_t::type1 node_type; |
| typedef typename vovocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (v1 o1 (c o2 v2)) |
| typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vocov->t0(); |
| const Type c = vocov->t1(); |
| const Type& v2 = vocov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vocov->f0(); |
| binary_functor_t f2 = vocov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) |
| return result; |
| if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vocovov_expression1 |
| { |
| typedef typename vocovov_t::type1 node_type; |
| typedef typename vocovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (c o1 (v1 o2 v2)) |
| typedef typename synthesize_covov_expression1::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c = covov->t0(); |
| const Type& v1 = covov->t1(); |
| const Type& v2 = covov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(covov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = covov->f0(); |
| binary_functor_t f2 = covov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_covovov_expression1 |
| { |
| typedef typename covovov_t::type1 node_type; |
| typedef typename covovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c o0 (v0 o1 (v1 o2 v2)) |
| typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[1]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovov->f0(); |
| binary_functor_t f2 = vovov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) |
| return result; |
| if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_covocov_expression1 |
| { |
| typedef typename covocov_t::type1 node_type; |
| typedef typename covocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c0 o0 (v0 o1 (c1 o2 v1)) |
| typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vocov->t0(); |
| const Type c1 = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vocov->f0(); |
| binary_functor_t f2 = vocov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vocovoc_expression1 |
| { |
| typedef typename vocovoc_t::type1 node_type; |
| typedef typename vocovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (c0 o1 (v1 o2 c2)) |
| typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; |
| |
| const lcl_covoc_t* covoc = static_cast<const lcl_covoc_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c0 = covoc->t0(); |
| const Type& v1 = covoc->t1(); |
| const Type c1 = covoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = covoc->f0(); |
| binary_functor_t f2 = covoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_covovoc_expression1 |
| { |
| typedef typename covovoc_t::type1 node_type; |
| typedef typename covovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c0 o0 (v0 o1 (v1 o2 c1)) |
| typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vovoc->t0(); |
| const Type& v1 = vovoc->t1(); |
| const Type c1 = vovoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovoc->f0(); |
| binary_functor_t f2 = vovoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vococov_expression1 |
| { |
| typedef typename vococov_t::type1 node_type; |
| typedef typename vococov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 (c0 o1 (c1 o2 v1)) |
| typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; |
| |
| const lcl_cocov_t* cocov = static_cast<const lcl_cocov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c0 = cocov->t0(); |
| const Type c1 = cocov->t1(); |
| const Type& v1 = cocov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = cocov->f0(); |
| binary_functor_t f2 = cocov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); |
| } |
| }; |
| |
| struct synthesize_vovovov_expression2 |
| { |
| typedef typename vovovov_t::type2 node_type; |
| typedef typename vovovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 ((v1 o1 v2) o2 v3) |
| typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vovov->t0(); |
| const Type& v2 = vovov->t1(); |
| const Type& v3 = vovov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovov->f0(); |
| binary_functor_t f2 = vovov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovovoc_expression2 |
| { |
| typedef typename vovovoc_t::type2 node_type; |
| typedef typename vovovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 ((v1 o1 v2) o2 c) |
| typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vovoc->t0(); |
| const Type& v2 = vovoc->t1(); |
| const Type c = vovoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovoc->f0(); |
| binary_functor_t f2 = vovoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vovocov_expression2 |
| { |
| typedef typename vovocov_t::type2 node_type; |
| typedef typename vovocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 ((v1 o1 c) o2 v2) |
| typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type& v1 = vocov->t0(); |
| const Type c = vocov->t1(); |
| const Type& v2 = vocov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vocov->f0(); |
| binary_functor_t f2 = vocov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vocovov_expression2 |
| { |
| typedef typename vocovov_t::type2 node_type; |
| typedef typename vocovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 ((c o1 v1) o2 v2) |
| typedef typename synthesize_covov_expression0::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c = covov->t0(); |
| const Type& v1 = covov->t1(); |
| const Type& v2 = covov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(covov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = covov->f0(); |
| binary_functor_t f2 = covov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covovov_expression2 |
| { |
| typedef typename covovov_t::type2 node_type; |
| typedef typename covovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c o0 ((v1 o1 v2) o2 v3) |
| typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[1]); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovov->f0(); |
| binary_functor_t f2 = vovov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covocov_expression2 |
| { |
| typedef typename covocov_t::type2 node_type; |
| typedef typename covocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c0 o0 ((v0 o1 c1) o2 v1) |
| typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vocov->t0(); |
| const Type c1 = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vocov->f0(); |
| binary_functor_t f2 = vocov->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vocovoc_expression2 |
| { |
| typedef typename vocovoc_t::type2 node_type; |
| typedef typename vocovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // v0 o0 ((c0 o1 v1) o2 c1) |
| typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; |
| |
| const lcl_covoc_t* covoc = static_cast<const lcl_covoc_t*>(branch[1]); |
| const Type& v0 = static_cast<details::variable_node<Type>*>(branch[0])->ref(); |
| const Type c0 = covoc->t0(); |
| const Type& v1 = covoc->t1(); |
| const Type c1 = covoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = covoc->f0(); |
| binary_functor_t f2 = covoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_covovoc_expression2 |
| { |
| typedef typename covovoc_t::type2 node_type; |
| typedef typename covovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // c0 o0 ((v0 o1 v1) o2 c1) |
| typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[1]); |
| const Type c0 = static_cast<details::literal_node<Type>*>(branch[0])->value(); |
| const Type& v0 = vovoc->t0(); |
| const Type& v1 = vovoc->t1(); |
| const Type c1 = vovoc->t2(); |
| const details::operator_type o0 = operation; |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); |
| |
| binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); |
| binary_functor_t f1 = vovoc->f0(); |
| binary_functor_t f2 = vovoc->f1(); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o0,f0)) |
| return error_node(); |
| |
| exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); |
| } |
| }; |
| |
| struct synthesize_vococov_expression2 |
| { |
| typedef typename vococov_t::type2 node_type; |
| static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) |
| { |
| // v0 o0 ((c0 o1 c1) o2 v1) - Not possible |
| exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); |
| return error_node(); |
| } |
| |
| static inline std::string id(expression_generator<Type>&, |
| const details::operator_type, const details::operator_type, const details::operator_type) |
| { |
| return "INVALID"; |
| } |
| }; |
| |
| struct synthesize_vovovov_expression3 |
| { |
| typedef typename vovovov_t::type3 node_type; |
| typedef typename vovovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 v1) o1 v2) o2 v3 |
| typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[0]); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const Type& v3 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovov->f0(); |
| binary_functor_t f1 = vovov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovovoc_expression3 |
| { |
| typedef typename vovovoc_t::type3 node_type; |
| typedef typename vovovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 v1) o1 v2) o2 c |
| typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[0]); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovov->f0(); |
| binary_functor_t f1 = vovov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovocov_expression3 |
| { |
| typedef typename vovocov_t::type3 node_type; |
| typedef typename vovocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 v1) o1 c) o2 v2 |
| typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[0]); |
| const Type& v0 = vovoc->t0(); |
| const Type& v1 = vovoc->t1(); |
| const Type c = vovoc->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovoc->f0(); |
| binary_functor_t f1 = vovoc->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vocovov_expression3 |
| { |
| typedef typename vocovov_t::type3 node_type; |
| typedef typename vocovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 c) o1 v1) o2 v2 |
| typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[0]); |
| const Type& v0 = vocov->t0(); |
| const Type c = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vocov->f0(); |
| binary_functor_t f1 = vocov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covovov_expression3 |
| { |
| typedef typename covovov_t::type3 node_type; |
| typedef typename covovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c o0 v0) o1 v1) o2 v2 |
| typedef typename synthesize_covov_expression0::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[0]); |
| const Type c = covov->t0(); |
| const Type& v0 = covov->t1(); |
| const Type& v1 = covov->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covov->f0(); |
| binary_functor_t f1 = covov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covocov_expression3 |
| { |
| typedef typename covocov_t::type3 node_type; |
| typedef typename covocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c0 o0 v0) o1 c1) o2 v1 |
| typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; |
| |
| const lcl_covoc_t* covoc = static_cast<const lcl_covoc_t*>(branch[0]); |
| const Type c0 = covoc->t0(); |
| const Type& v0 = covoc->t1(); |
| const Type c1 = covoc->t2(); |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covoc->f0(); |
| binary_functor_t f1 = covoc->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vocovoc_expression3 |
| { |
| typedef typename vocovoc_t::type3 node_type; |
| typedef typename vocovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 c0) o1 v1) o2 c1 |
| typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[0]); |
| const Type& v0 = vocov->t0(); |
| const Type c0 = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vocov->f0(); |
| binary_functor_t f1 = vocov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covovoc_expression3 |
| { |
| typedef typename covovoc_t::type3 node_type; |
| typedef typename covovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c0 o0 v0) o1 v1) o2 c1 |
| typedef typename synthesize_covov_expression0::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[0]); |
| const Type c0 = covov->t0(); |
| const Type& v0 = covov->t1(); |
| const Type& v1 = covov->t2(); |
| const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covov->f0(); |
| binary_functor_t f1 = covov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vococov_expression3 |
| { |
| typedef typename vococov_t::type3 node_type; |
| typedef typename vococov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 c0) o1 c1) o2 v1 |
| typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; |
| |
| const lcl_vococ_t* vococ = static_cast<const lcl_vococ_t*>(branch[0]); |
| const Type& v0 = vococ->t0(); |
| const Type c0 = vococ->t1(); |
| const Type c1 = vococ->t2(); |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vococ->f0(); |
| binary_functor_t f1 = vococ->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovovov_expression4 |
| { |
| typedef typename vovovov_t::type4 node_type; |
| typedef typename vovovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // (v0 o0 (v1 o1 v2)) o2 v3 |
| typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[0]); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const Type& v3 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovov->f0(); |
| binary_functor_t f1 = vovov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovovoc_expression4 |
| { |
| typedef typename vovovoc_t::type4 node_type; |
| typedef typename vovovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 (v1 o1 v2)) o2 c) |
| typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; |
| |
| const lcl_vovov_t* vovov = static_cast<const lcl_vovov_t*>(branch[0]); |
| const Type& v0 = vovov->t0(); |
| const Type& v1 = vovov->t1(); |
| const Type& v2 = vovov->t2(); |
| const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovov->f0(); |
| binary_functor_t f1 = vovov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vovocov_expression4 |
| { |
| typedef typename vovocov_t::type4 node_type; |
| typedef typename vovocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 (v1 o1 c)) o2 v1) |
| typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; |
| |
| const lcl_vovoc_t* vovoc = static_cast<const lcl_vovoc_t*>(branch[0]); |
| const Type& v0 = vovoc->t0(); |
| const Type& v1 = vovoc->t1(); |
| const Type c = vovoc->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vovoc->f0(); |
| binary_functor_t f1 = vovoc->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vocovov_expression4 |
| { |
| typedef typename vocovov_t::type4 node_type; |
| typedef typename vocovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 (c o1 v1)) o2 v2) |
| typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[0]); |
| const Type& v0 = vocov->t0(); |
| const Type c = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vocov->f0(); |
| binary_functor_t f1 = vocov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covovov_expression4 |
| { |
| typedef typename covovov_t::type4 node_type; |
| typedef typename covovov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c o0 (v0 o1 v1)) o2 v2) |
| typedef typename synthesize_covov_expression1::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[0]); |
| const Type c = covov->t0(); |
| const Type& v0 = covov->t1(); |
| const Type& v1 = covov->t2(); |
| const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covov->f0(); |
| binary_functor_t f1 = covov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covocov_expression4 |
| { |
| typedef typename covocov_t::type4 node_type; |
| typedef typename covocov_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c0 o0 (v0 o1 c1)) o2 v1) |
| typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; |
| |
| const lcl_covoc_t* covoc = static_cast<const lcl_covoc_t*>(branch[0]); |
| const Type c0 = covoc->t0(); |
| const Type& v0 = covoc->t1(); |
| const Type c1 = covoc->t2(); |
| const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref(); |
| const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covoc->f0(); |
| binary_functor_t f1 = covoc->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vocovoc_expression4 |
| { |
| typedef typename vocovoc_t::type4 node_type; |
| typedef typename vocovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((v0 o0 (c0 o1 v1)) o2 c1) |
| typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; |
| |
| const lcl_vocov_t* vocov = static_cast<const lcl_vocov_t*>(branch[0]); |
| const Type& v0 = vocov->t0(); |
| const Type c0 = vocov->t1(); |
| const Type& v1 = vocov->t2(); |
| const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = vocov->f0(); |
| binary_functor_t f1 = vocov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_covovoc_expression4 |
| { |
| typedef typename covovoc_t::type4 node_type; |
| typedef typename covovoc_t::sf4_type sf4_type; |
| typedef typename node_type::T0 T0; |
| typedef typename node_type::T1 T1; |
| typedef typename node_type::T2 T2; |
| typedef typename node_type::T3 T3; |
| |
| static inline expression_node_ptr process(expression_generator<Type>& expr_gen, |
| const details::operator_type& operation, |
| expression_node_ptr (&branch)[2]) |
| { |
| // ((c0 o0 (v0 o1 v1)) o2 c1) |
| typedef typename synthesize_covov_expression1::node_type lcl_covov_t; |
| |
| const lcl_covov_t* covov = static_cast<const lcl_covov_t*>(branch[0]); |
| const Type c0 = covov->t0(); |
| const Type& v0 = covov->t1(); |
| const Type& v1 = covov->t2(); |
| const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value(); |
| const details::operator_type o0 = expr_gen.get_operator(covov->f0()); |
| const details::operator_type o1 = expr_gen.get_operator(covov->f1()); |
| const details::operator_type o2 = operation; |
| |
| binary_functor_t f0 = covov->f0(); |
| binary_functor_t f1 = covov->f1(); |
| binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); |
| |
| details::free_node(*(expr_gen.node_allocator_),branch[0]); |
| details::free_node(*(expr_gen.node_allocator_),branch[1]); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) |
| return result; |
| else if (!expr_gen.valid_operator(o2,f2)) |
| return error_node(); |
| |
| exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); |
| |
| return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); |
| } |
| |
| static inline std::string id(expression_generator<Type>& expr_gen, |
| const details::operator_type o0, |
| const details::operator_type o1, |
| const details::operator_type o2) |
| { |
| return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); |
| } |
| }; |
| |
| struct synthesize_vococov_expression4 |
| { |
| typedef typename vococov_t::type4 node_type; |
| static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) |
| { |
| // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible |
| exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); |
| return error_node(); |
| } |
| |
| static inline std::string id(expression_generator<Type>&, |
| const details::operator_type, const details::operator_type, const details::operator_type) |
| { |
| return "INVALID"; |
| } |
| }; |
| #endif |
| |
| inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| // Definition: uv o uv |
| details::operator_type o0 = static_cast<details::uv_base_node<Type>*>(branch[0])->operation(); |
| details::operator_type o1 = static_cast<details::uv_base_node<Type>*>(branch[1])->operation(); |
| const Type& v0 = static_cast<details::uv_base_node<Type>*>(branch[0])->v(); |
| const Type& v1 = static_cast<details::uv_base_node<Type>*>(branch[1])->v(); |
| unary_functor_t u0 = reinterpret_cast<unary_functor_t> (0); |
| unary_functor_t u1 = reinterpret_cast<unary_functor_t> (0); |
| binary_functor_t f = reinterpret_cast<binary_functor_t>(0); |
| |
| if (!valid_operator(o0,u0)) |
| return error_node(); |
| else if (!valid_operator(o1,u1)) |
| return error_node(); |
| else if (!valid_operator(operation,f)) |
| return error_node(); |
| |
| expression_node_ptr result = error_node(); |
| |
| if ( |
| (details::e_neg == o0) && |
| (details::e_neg == o1) |
| ) |
| { |
| switch (operation) |
| { |
| // (-v0 + -v1) --> -(v0 + v1) |
| case details::e_add : result = (*this)(details::e_neg, |
| node_allocator_-> |
| allocate_rr<typename details:: |
| vov_node<Type,details::add_op<Type> > >(v0,v1)); |
| exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); |
| break; |
| |
| // (-v0 - -v1) --> (v1 - v0) |
| case details::e_sub : result = node_allocator_-> |
| allocate_rr<typename details:: |
| vov_node<Type,details::sub_op<Type> > >(v1,v0); |
| exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); |
| break; |
| |
| // (-v0 * -v1) --> (v0 * v1) |
| case details::e_mul : result = node_allocator_-> |
| allocate_rr<typename details:: |
| vov_node<Type,details::mul_op<Type> > >(v0,v1); |
| exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); |
| break; |
| |
| // (-v0 / -v1) --> (v0 / v1) |
| case details::e_div : result = node_allocator_-> |
| allocate_rr<typename details:: |
| vov_node<Type,details::div_op<Type> > >(v0,v1); |
| exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); |
| break; |
| |
| default : break; |
| } |
| } |
| |
| if (0 == result) |
| { |
| result = node_allocator_-> |
| allocate_rrrrr<typename details::uvouv_node<Type> >(v0,v1,u0,u1,f); |
| } |
| |
| details::free_all_nodes(*node_allocator_,branch); |
| return result; |
| } |
| |
| #undef basic_opr_switch_statements |
| #undef extended_opr_switch_statements |
| #undef unary_opr_switch_statements |
| |
| #ifndef exprtk_disable_string_capabilities |
| |
| #define string_opr_switch_statements \ |
| case_stmt(details:: e_lt ,details:: lt_op) \ |
| case_stmt(details:: e_lte ,details:: lte_op) \ |
| case_stmt(details:: e_gt ,details:: gt_op) \ |
| case_stmt(details:: e_gte ,details:: gte_op) \ |
| case_stmt(details:: e_eq ,details:: eq_op) \ |
| case_stmt(details:: e_ne ,details:: ne_op) \ |
| case_stmt(details::e_in ,details:: in_op) \ |
| case_stmt(details::e_like ,details:: like_op) \ |
| case_stmt(details::e_ilike,details::ilike_op) \ |
| |
| template <typename T0, typename T1> |
| inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, |
| T0 s0, T1 s1, |
| range_t rp0) |
| { |
| switch (opr) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate_ttt<typename details::str_xrox_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ |
| (s0,s1,rp0); \ |
| |
| string_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename T0, typename T1> |
| inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, |
| T0 s0, T1 s1, |
| range_t rp1) |
| { |
| switch (opr) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate_ttt<typename details::str_xoxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ |
| (s0,s1,rp1); \ |
| |
| string_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename T0, typename T1> |
| inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, |
| T0 s0, T1 s1, |
| range_t rp0, range_t rp1) |
| { |
| switch (opr) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate_tttt<typename details::str_xroxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ |
| (s0,s1,rp0,rp1); \ |
| |
| string_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| template <typename T0, typename T1> |
| inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) |
| { |
| switch (opr) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate_tt<typename details::sos_node<Type,T0,T1,op1<Type> >,T0,T1>(s0,s1); \ |
| |
| string_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| |
| inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::stringvar_node<Type>*>(branch[0])->ref(); |
| std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref(); |
| |
| return synthesize_sos_expression_impl<std::string&,std::string&>(opr,s0,s1); |
| } |
| |
| inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::string_range_node<Type>*>(branch[0])->ref (); |
| std::string& s1 = static_cast<details::stringvar_node<Type>*> (branch[1])->ref (); |
| range_t rp0 = static_cast<details::string_range_node<Type>*>(branch[0])->range(); |
| |
| static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[0]); |
| |
| return synthesize_str_xrox_expression_impl<std::string&,std::string&>(opr,s0,s1,rp0); |
| } |
| |
| inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::stringvar_node<Type>*> (branch[0])->ref (); |
| std::string& s1 = static_cast<details::string_range_node<Type>*>(branch[1])->ref (); |
| range_t rp1 = static_cast<details::string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xoxr_expression_impl<std::string&,std::string&>(opr,s0,s1,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::stringvar_node<Type>*> (branch[0])->ref (); |
| std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); |
| range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xoxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::string_range_node<Type>*>(branch[0])->ref (); |
| std::string& s1 = static_cast<details::string_range_node<Type>*>(branch[1])->ref (); |
| range_t rp0 = static_cast<details::string_range_node<Type>*>(branch[0])->range(); |
| range_t rp1 = static_cast<details::string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xroxr_expression_impl<std::string&,std::string&>(opr,s0,s1,rp0,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast< details::stringvar_node<Type>*>(branch[0])->ref(); |
| std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); |
| |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_sos_expression_impl<std::string&, const std::string>(opr,s0,s1); |
| } |
| |
| inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); |
| std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); |
| |
| details::free_node(*node_allocator_,branch[0]); |
| |
| return synthesize_sos_expression_impl<const std::string,std::string&>(opr,s0,s1); |
| } |
| |
| inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str (); |
| std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref (); |
| range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); |
| |
| static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xoxr_expression_impl<const std::string,std::string&>(opr,s0,s1,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::string_range_node<Type>*> (branch[0])->ref (); |
| std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str (); |
| range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range(); |
| |
| static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xrox_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0); |
| } |
| |
| inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string& s0 = static_cast<details::string_range_node<Type>*> (branch[0])->ref (); |
| std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); |
| range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range(); |
| range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::string_range_node<Type>*> (branch[0])->range_ref().clear(); |
| static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xroxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| const std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); |
| const std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); |
| |
| expression_node_ptr result = error_node(); |
| |
| if (details::e_add == opr) |
| result = node_allocator_->allocate_c<details::string_literal_node<Type> >(s0 + s1); |
| else if (details::e_in == opr) |
| result = node_allocator_->allocate_c<details::literal_node<Type> >(details::in_op<Type>::process(s0,s1)); |
| else if (details::e_like == opr) |
| result = node_allocator_->allocate_c<details::literal_node<Type> >(details::like_op<Type>::process(s0,s1)); |
| else if (details::e_ilike == opr) |
| result = node_allocator_->allocate_c<details::literal_node<Type> >(details::ilike_op<Type>::process(s0,s1)); |
| else |
| { |
| expression_node_ptr temp = synthesize_sos_expression_impl<const std::string, const std::string>(opr,s0,s1); |
| Type v = temp->value(); |
| details::free_node(*node_allocator_,temp); |
| result = node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return result; |
| } |
| |
| inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| const std::string s0 = static_cast<details::string_literal_node<Type>*> (branch[0])->str (); |
| std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); |
| range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[0]); |
| free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xoxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); |
| std::string& s1 = static_cast<details::stringvar_node<Type>*> (branch[1])->ref (); |
| range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[0]); |
| |
| return synthesize_str_xrox_expression_impl<const std::string,std::string&>(opr,s0,s1,rp0); |
| } |
| |
| inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); |
| std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref (); |
| range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); |
| range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| static_cast<details::string_range_node<Type>*> (branch[1])->range_ref().clear(); |
| |
| free_node(*node_allocator_,branch[0]); |
| free_node(*node_allocator_,branch[1]); |
| |
| return synthesize_str_xroxr_expression_impl<const std::string,std::string&>(opr,s0,s1,rp0,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); |
| const std::string s1 = static_cast<details::string_literal_node<Type>*> (branch[1])->str (); |
| range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return synthesize_str_xrox_expression_impl<const std::string,std::string>(opr,s0,s1,rp0); |
| } |
| |
| inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); |
| std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); |
| range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); |
| range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); |
| |
| static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); |
| static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); |
| |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return synthesize_str_xroxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp0,rp1); |
| } |
| |
| inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| switch (opr) |
| { |
| #define case_stmt(op0,op1) \ |
| case op0 : return node_allocator_-> \ |
| allocate_ttt<typename details::str_sogens_node<Type,op1<Type> > > \ |
| (opr,branch[0],branch[1]); \ |
| |
| string_opr_switch_statements |
| #undef case_stmt |
| default : return error_node(); |
| } |
| } |
| #endif |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) |
| { |
| if ((0 == branch[0]) || (0 == branch[1])) |
| { |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| |
| const bool b0_is_s = details::is_string_node (branch[0]); |
| const bool b0_is_cs = details::is_const_string_node (branch[0]); |
| const bool b0_is_sr = details::is_string_range_node (branch[0]); |
| const bool b0_is_csr = details::is_const_string_range_node(branch[0]); |
| |
| const bool b1_is_s = details::is_string_node (branch[1]); |
| const bool b1_is_cs = details::is_const_string_node (branch[1]); |
| const bool b1_is_sr = details::is_string_range_node (branch[1]); |
| const bool b1_is_csr = details::is_const_string_range_node(branch[1]); |
| |
| const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || |
| details::is_genricstring_range_node(branch[0]) || |
| details::is_string_concat_node (branch[0]) || |
| details::is_string_function_node (branch[0]) || |
| details::is_string_condition_node (branch[0]) || |
| details::is_string_ccondition_node (branch[0]) ; |
| |
| const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || |
| details::is_genricstring_range_node(branch[1]) || |
| details::is_string_concat_node (branch[1]) || |
| details::is_string_function_node (branch[1]) || |
| details::is_string_condition_node (branch[1]) || |
| details::is_string_ccondition_node (branch[1]) ; |
| |
| if (details::e_add == opr) |
| { |
| if (!b0_is_cs || !b1_is_cs) |
| { |
| return synthesize_expression<string_concat_node_t,2>(opr,branch); |
| } |
| } |
| |
| if (b0_is_gen || b1_is_gen) |
| { |
| return synthesize_strogen_expression(opr,branch); |
| } |
| else if (b0_is_s) |
| { |
| if (b1_is_s ) return synthesize_sos_expression (opr,branch); |
| else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); |
| else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); |
| else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); |
| } |
| else if (b0_is_cs) |
| { |
| if (b1_is_s ) return synthesize_csos_expression (opr,branch); |
| else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); |
| else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); |
| else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); |
| } |
| else if (b0_is_sr) |
| { |
| if (b1_is_s ) return synthesize_sros_expression (opr,branch); |
| else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); |
| else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); |
| else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); |
| } |
| else if (b0_is_csr) |
| { |
| if (b1_is_s ) return synthesize_csros_expression (opr,branch); |
| else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); |
| else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); |
| else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); |
| } |
| |
| return error_node(); |
| } |
| #else |
| inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) |
| { |
| details::free_all_nodes(*node_allocator_,branch); |
| return error_node(); |
| } |
| #endif |
| |
| #ifndef exprtk_disable_string_capabilities |
| inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) |
| { |
| if (details::e_inrange != opr) |
| return error_node(); |
| else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) |
| { |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if ( |
| details::is_const_string_node(branch[0]) && |
| details::is_const_string_node(branch[1]) && |
| details::is_const_string_node(branch[2]) |
| ) |
| { |
| const std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); |
| const std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); |
| const std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); |
| |
| Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); |
| details::free_all_nodes(*node_allocator_,branch); |
| |
| return node_allocator_->allocate_c<details::literal_node<Type> >(v); |
| } |
| else if ( |
| details::is_string_node(branch[0]) && |
| details::is_string_node(branch[1]) && |
| details::is_string_node(branch[2]) |
| ) |
| { |
| std::string& s0 = static_cast<details::stringvar_node<Type>*>(branch[0])->ref(); |
| std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref(); |
| std::string& s2 = static_cast<details::stringvar_node<Type>*>(branch[2])->ref(); |
| |
| typedef typename details::sosos_node<Type,std::string&,std::string&,std::string&,details::inrange_op<Type> > inrange_t; |
| |
| return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string&>(s0,s1,s2); |
| } |
| else if ( |
| details::is_const_string_node(branch[0]) && |
| details::is_string_node(branch[1]) && |
| details::is_const_string_node(branch[2]) |
| ) |
| { |
| std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); |
| std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); |
| std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); |
| |
| typedef typename details::sosos_node<Type,std::string,std::string&,std::string,details::inrange_op<Type> > inrange_t; |
| |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[2]); |
| |
| return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string>(s0,s1,s2); |
| } |
| else if ( |
| details::is_string_node(branch[0]) && |
| details::is_const_string_node(branch[1]) && |
| details::is_string_node(branch[2]) |
| ) |
| { |
| std::string& s0 = static_cast< details::stringvar_node<Type>*>(branch[0])->ref(); |
| std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); |
| std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); |
| |
| typedef typename details::sosos_node<Type,std::string&,std::string,std::string&,details::inrange_op<Type> > inrange_t; |
| |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return node_allocator_->allocate_type<inrange_t,std::string&,std::string,std::string&>(s0,s1,s2); |
| } |
| else if ( |
| details::is_string_node(branch[0]) && |
| details::is_string_node(branch[1]) && |
| details::is_const_string_node(branch[2]) |
| ) |
| { |
| std::string& s0 = static_cast< details::stringvar_node<Type>*>(branch[0])->ref(); |
| std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); |
| std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); |
| |
| typedef typename details::sosos_node<Type,std::string&,std::string&,std::string,details::inrange_op<Type> > inrange_t; |
| |
| details::free_node(*node_allocator_,branch[2]); |
| |
| return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string>(s0,s1,s2); |
| } |
| else if ( |
| details::is_const_string_node(branch[0]) && |
| details:: is_string_node(branch[1]) && |
| details:: is_string_node(branch[2]) |
| ) |
| { |
| std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); |
| std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); |
| std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); |
| |
| typedef typename details::sosos_node<Type,std::string,std::string&,std::string&,details::inrange_op<Type> > inrange_t; |
| |
| details::free_node(*node_allocator_,branch[0]); |
| |
| return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string&>(s0,s1,s2); |
| } |
| else |
| return error_node(); |
| } |
| #else |
| inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) |
| { |
| details::free_all_nodes(*node_allocator_,branch); |
| return error_node(); |
| } |
| #endif |
| |
| inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) |
| { |
| /* |
| Note: The following are the type promotion rules |
| that relate to operations that include 'null': |
| 0. null ==/!= null --> true false |
| 1. null operation null --> null |
| 2. x ==/!= null --> true/false |
| 3. null ==/!= x --> true/false |
| 4. x operation null --> x |
| 5. null operation x --> x |
| */ |
| |
| typedef typename details::null_eq_node<T> nulleq_node_t; |
| |
| bool b0_null = details::is_null_node(branch[0]); |
| bool b1_null = details::is_null_node(branch[1]); |
| |
| if (b0_null && b1_null) |
| { |
| expression_node_ptr result = error_node(); |
| |
| if (details::e_eq == operation) |
| result = node_allocator_->allocate_c<literal_node_t>(T(1)); |
| else if (details::e_ne == operation) |
| result = node_allocator_->allocate_c<literal_node_t>(T(0)); |
| |
| if (result) |
| { |
| details::free_node(*node_allocator_,branch[0]); |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return result; |
| } |
| |
| details::free_node(*node_allocator_,branch[1]); |
| |
| return branch[0]; |
| } |
| else if (details::e_eq == operation) |
| { |
| expression_node_ptr result = node_allocator_-> |
| allocate_rc<nulleq_node_t>(branch[b0_null ? 0 : 1],true); |
| |
| details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); |
| |
| return result; |
| } |
| else if (details::e_ne == operation) |
| { |
| expression_node_ptr result = node_allocator_-> |
| allocate_rc<nulleq_node_t>(branch[b0_null ? 0 : 1],false); |
| |
| details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); |
| |
| return result; |
| } |
| else if (b0_null) |
| { |
| details::free_node(*node_allocator_,branch[0]); |
| branch[0] = branch[1]; |
| branch[1] = error_node(); |
| } |
| else if (b1_null) |
| { |
| details::free_node(*node_allocator_,branch[1]); |
| branch[1] = error_node(); |
| } |
| |
| if ( |
| (details::e_add == operation) || (details::e_sub == operation) || |
| (details::e_mul == operation) || (details::e_div == operation) || |
| (details::e_mod == operation) || (details::e_pow == operation) |
| ) |
| { |
| return branch[0]; |
| } |
| else if ( |
| (details::e_lt == operation) || (details::e_lte == operation) || |
| (details::e_gt == operation) || (details::e_gte == operation) || |
| (details::e_and == operation) || (details::e_nand == operation) || |
| (details::e_or == operation) || (details::e_nor == operation) || |
| (details::e_xor == operation) || (details::e_xnor == operation) || |
| (details::e_in == operation) || (details::e_like == operation) || |
| (details::e_ilike == operation) |
| ) |
| { |
| return node_allocator_->allocate_c<literal_node_t>(T(0)); |
| } |
| |
| details::free_node(*node_allocator_,branch[0]); |
| |
| return node_allocator_->allocate<details::null_node<Type> >(); |
| } |
| |
| template <typename NodeType, std::size_t N> |
| inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) |
| { |
| if ( |
| (details::e_in == operation) || |
| (details::e_like == operation) || |
| (details::e_ilike == operation) |
| ) |
| return error_node(); |
| else if (!details::all_nodes_valid<N>(branch)) |
| { |
| free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else if ((details::e_default != operation)) |
| { |
| // Attempt simple constant folding optimisation. |
| expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(operation,branch); |
| |
| if (is_constant_foldable<N>(branch)) |
| { |
| Type v = expression_point->value(); |
| details::free_node(*node_allocator_,expression_point); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| else |
| return expression_point; |
| } |
| else |
| return error_node(); |
| } |
| |
| template <typename NodeType, std::size_t N> |
| inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) |
| { |
| if (!details::all_nodes_valid<N>(branch)) |
| { |
| free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| |
| typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t; |
| |
| // Attempt simple constant folding optimisation. |
| |
| expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(f); |
| function_N_node_t* func_node_ptr = dynamic_cast<function_N_node_t*>(expression_point); |
| |
| if (0 == func_node_ptr) |
| { |
| free_all_nodes(*node_allocator_,branch); |
| |
| return error_node(); |
| } |
| else |
| func_node_ptr->init_branches(branch); |
| |
| if (is_constant_foldable<N>(branch) && !f->has_side_effects()) |
| { |
| Type v = expression_point->value(); |
| details::free_node(*node_allocator_,expression_point); |
| |
| return node_allocator_->allocate<literal_node_t>(v); |
| } |
| |
| parser_->state_.activate_side_effect("synthesize_expression(function<NT,N>)"); |
| |
| return expression_point; |
| } |
| |
| bool strength_reduction_enabled_; |
| details::node_allocator* node_allocator_; |
| synthesize_map_t synthesize_map_; |
| unary_op_map_t* unary_op_map_; |
| binary_op_map_t* binary_op_map_; |
| inv_binary_op_map_t* inv_binary_op_map_; |
| sf3_map_t* sf3_map_; |
| sf4_map_t* sf4_map_; |
| parser_t* parser_; |
| }; |
| |
| inline void set_error(const parser_error::type& error_type) |
| { |
| error_list_.push_back(error_type); |
| } |
| |
| inline void remove_last_error() |
| { |
| if (!error_list_.empty()) |
| { |
| error_list_.pop_back(); |
| } |
| } |
| |
| inline void set_synthesis_error(const std::string& synthesis_error_message) |
| { |
| if (synthesis_error_.empty()) |
| { |
| synthesis_error_ = synthesis_error_message; |
| } |
| } |
| |
| inline void register_local_vars(expression<T>& e) |
| { |
| for (std::size_t i = 0; i < sem_.size(); ++i) |
| { |
| scope_element& se = sem_.get_element(i); |
| |
| if ( |
| (scope_element::e_variable == se.type) || |
| (scope_element::e_vecelem == se.type) |
| ) |
| { |
| if (se.var_node) |
| { |
| e.register_local_var(se.var_node); |
| } |
| |
| if (se.data) |
| { |
| e.register_local_data(se.data,1,0); |
| } |
| } |
| else if (scope_element::e_vector == se.type) |
| { |
| if (se.vec_node) |
| { |
| e.register_local_var(se.vec_node); |
| } |
| |
| if (se.data) |
| { |
| e.register_local_data(se.data,se.size,1); |
| } |
| } |
| #ifndef exprtk_disable_string_capabilities |
| else if (scope_element::e_string == se.type) |
| { |
| if (se.str_node) |
| { |
| e.register_local_var(se.str_node); |
| } |
| |
| if (se.data) |
| { |
| e.register_local_data(se.data,se.size,2); |
| } |
| } |
| #endif |
| |
| se.var_node = 0; |
| se.vec_node = 0; |
| #ifndef exprtk_disable_string_capabilities |
| se.str_node = 0; |
| #endif |
| se.data = 0; |
| se.ref_count = 0; |
| se.active = false; |
| } |
| } |
| |
| inline void register_return_results(expression<T>& e) |
| { |
| e.register_return_results(results_context_); |
| results_context_ = 0; |
| } |
| |
| inline void load_unary_operations_map(unary_op_map_t& m) |
| { |
| #define register_unary_op(Op,UnaryFunctor) \ |
| m.insert(std::make_pair(Op,UnaryFunctor<T>::process)); \ |
| |
| register_unary_op(details:: e_abs,details:: abs_op) |
| register_unary_op(details:: e_acos,details:: acos_op) |
| register_unary_op(details::e_acosh,details::acosh_op) |
| register_unary_op(details:: e_asin,details:: asin_op) |
| register_unary_op(details::e_asinh,details::asinh_op) |
| register_unary_op(details::e_atanh,details::atanh_op) |
| register_unary_op(details:: e_ceil,details:: ceil_op) |
| register_unary_op(details:: e_cos,details:: cos_op) |
| register_unary_op(details:: e_cosh,details:: cosh_op) |
| register_unary_op(details:: e_exp,details:: exp_op) |
| register_unary_op(details::e_expm1,details::expm1_op) |
| register_unary_op(details::e_floor,details::floor_op) |
| register_unary_op(details:: e_log,details:: log_op) |
| register_unary_op(details::e_log10,details::log10_op) |
| register_unary_op(details:: e_log2,details:: log2_op) |
| register_unary_op(details::e_log1p,details::log1p_op) |
| register_unary_op(details:: e_neg,details:: neg_op) |
| register_unary_op(details:: e_pos,details:: pos_op) |
| register_unary_op(details::e_round,details::round_op) |
| register_unary_op(details:: e_sin,details:: sin_op) |
| register_unary_op(details:: e_sinc,details:: sinc_op) |
| register_unary_op(details:: e_sinh,details:: sinh_op) |
| register_unary_op(details:: e_sqrt,details:: sqrt_op) |
| register_unary_op(details:: e_tan,details:: tan_op) |
| register_unary_op(details:: e_tanh,details:: tanh_op) |
| register_unary_op(details:: e_cot,details:: cot_op) |
| register_unary_op(details:: e_sec,details:: sec_op) |
| register_unary_op(details:: e_csc,details:: csc_op) |
| register_unary_op(details:: e_r2d,details:: r2d_op) |
| register_unary_op(details:: e_d2r,details:: d2r_op) |
| register_unary_op(details:: e_d2g,details:: d2g_op) |
| register_unary_op(details:: e_g2d,details:: g2d_op) |
| register_unary_op(details:: e_notl,details:: notl_op) |
| register_unary_op(details:: e_sgn,details:: sgn_op) |
| register_unary_op(details:: e_erf,details:: erf_op) |
| register_unary_op(details:: e_erfc,details:: erfc_op) |
| register_unary_op(details:: e_ncdf,details:: ncdf_op) |
| register_unary_op(details:: e_frac,details:: frac_op) |
| register_unary_op(details::e_trunc,details::trunc_op) |
| #undef register_unary_op |
| } |
| |
| inline void load_binary_operations_map(binary_op_map_t& m) |
| { |
| typedef typename binary_op_map_t::value_type value_type; |
| |
| #define register_binary_op(Op,BinaryFunctor) \ |
| m.insert(value_type(Op,BinaryFunctor<T>::process)); \ |
| |
| register_binary_op(details:: e_add,details:: add_op) |
| register_binary_op(details:: e_sub,details:: sub_op) |
| register_binary_op(details:: e_mul,details:: mul_op) |
| register_binary_op(details:: e_div,details:: div_op) |
| register_binary_op(details:: e_mod,details:: mod_op) |
| register_binary_op(details:: e_pow,details:: pow_op) |
| register_binary_op(details:: e_lt,details:: lt_op) |
| register_binary_op(details:: e_lte,details:: lte_op) |
| register_binary_op(details:: e_gt,details:: gt_op) |
| register_binary_op(details:: e_gte,details:: gte_op) |
| register_binary_op(details:: e_eq,details:: eq_op) |
| register_binary_op(details:: e_ne,details:: ne_op) |
| register_binary_op(details:: e_and,details:: and_op) |
| register_binary_op(details::e_nand,details::nand_op) |
| register_binary_op(details:: e_or,details:: or_op) |
| register_binary_op(details:: e_nor,details:: nor_op) |
| register_binary_op(details:: e_xor,details:: xor_op) |
| register_binary_op(details::e_xnor,details::xnor_op) |
| #undef register_binary_op |
| } |
| |
| inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) |
| { |
| typedef typename inv_binary_op_map_t::value_type value_type; |
| |
| #define register_binary_op(Op,BinaryFunctor) \ |
| m.insert(value_type(BinaryFunctor<T>::process,Op)); \ |
| |
| register_binary_op(details:: e_add,details:: add_op) |
| register_binary_op(details:: e_sub,details:: sub_op) |
| register_binary_op(details:: e_mul,details:: mul_op) |
| register_binary_op(details:: e_div,details:: div_op) |
| register_binary_op(details:: e_mod,details:: mod_op) |
| register_binary_op(details:: e_pow,details:: pow_op) |
| register_binary_op(details:: e_lt,details:: lt_op) |
| register_binary_op(details:: e_lte,details:: lte_op) |
| register_binary_op(details:: e_gt,details:: gt_op) |
| register_binary_op(details:: e_gte,details:: gte_op) |
| register_binary_op(details:: e_eq,details:: eq_op) |
| register_binary_op(details:: e_ne,details:: ne_op) |
| register_binary_op(details:: e_and,details:: and_op) |
| register_binary_op(details::e_nand,details::nand_op) |
| register_binary_op(details:: e_or,details:: or_op) |
| register_binary_op(details:: e_nor,details:: nor_op) |
| register_binary_op(details:: e_xor,details:: xor_op) |
| register_binary_op(details::e_xnor,details::xnor_op) |
| #undef register_binary_op |
| } |
| |
| inline void load_sf3_map(sf3_map_t& sf3_map) |
| { |
| typedef std::pair<trinary_functor_t,details::operator_type> pair_t; |
| |
| #define register_sf3(Op) \ |
| sf3_map[details::sf##Op##_op<T>::id()] = pair_t(details::sf##Op##_op<T>::process,details::e_sf##Op); \ |
| |
| register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) |
| register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) |
| register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) |
| register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) |
| register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) |
| register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) |
| register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) |
| register_sf3(28) register_sf3(29) register_sf3(30) |
| #undef register_sf3 |
| } |
| |
| inline void load_sf4_map(sf4_map_t& sf4_map) |
| { |
| typedef std::pair<quaternary_functor_t,details::operator_type> pair_t; |
| |
| #define register_sf4(Op) \ |
| sf4_map[details::sf##Op##_op<T>::id()] = pair_t(details::sf##Op##_op<T>::process,details::e_sf##Op); \ |
| |
| register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) |
| register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) |
| register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) |
| register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) |
| register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) |
| register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) |
| register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) |
| register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) |
| register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) |
| #undef register_sf4 |
| |
| #define register_sf4ext(Op) \ |
| sf4_map[details::sfext##Op##_op<T>::id()] = pair_t(details::sfext##Op##_op<T>::process,details::e_sf4ext##Op); \ |
| |
| register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) |
| register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) |
| register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) |
| register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) |
| register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) |
| register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) |
| register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) |
| register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) |
| register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) |
| register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) |
| register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) |
| register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) |
| register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) |
| register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) |
| register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) |
| register_sf4ext(60) |
| #undef register_sf4ext |
| } |
| |
| inline results_context_t& results_ctx() |
| { |
| if (0 == results_context_) |
| { |
| results_context_ = new results_context_t(); |
| } |
| |
| return (*results_context_); |
| } |
| |
| inline void return_cleanup() |
| { |
| if (results_context_) |
| { |
| delete results_context_; |
| results_context_ = 0; |
| } |
| |
| state_.return_stmt_present = false; |
| } |
| |
| private: |
| |
| parser(const parser<T>&); |
| parser<T>& operator=(const parser<T>&); |
| |
| settings_store settings_; |
| expression_generator<T> expression_generator_; |
| details::node_allocator node_allocator_; |
| symtab_store symtab_store_; |
| dependent_entity_collector dec_; |
| std::deque<parser_error::type> error_list_; |
| std::deque<bool> brkcnt_list_; |
| parser_state state_; |
| bool resolve_unknown_symbol_; |
| results_context_t* results_context_; |
| unknown_symbol_resolver* unknown_symbol_resolver_; |
| unknown_symbol_resolver default_usr_; |
| base_ops_map_t base_ops_map_; |
| unary_op_map_t unary_op_map_; |
| binary_op_map_t binary_op_map_; |
| inv_binary_op_map_t inv_binary_op_map_; |
| sf3_map_t sf3_map_; |
| sf4_map_t sf4_map_; |
| std::string synthesis_error_; |
| scope_element_manager sem_; |
| |
| lexer::helper::helper_assembly helper_assembly_; |
| |
| lexer::helper::commutative_inserter commutative_inserter_; |
| lexer::helper::operator_joiner operator_joiner_2_; |
| lexer::helper::operator_joiner operator_joiner_3_; |
| lexer::helper::symbol_replacer symbol_replacer_; |
| lexer::helper::bracket_checker bracket_checker_; |
| lexer::helper::numeric_checker numeric_checker_; |
| lexer::helper::sequence_validator sequence_validator_; |
| }; |
| |
| template <typename T> |
| inline T integrate(const expression<T>& e, |
| T& x, |
| const T& r0, const T& r1, |
| const std::size_t number_of_intervals = 1000000) |
| { |
| if (r0 > r1) |
| return T(0); |
| |
| T h = (r1 - r0) / (T(2) * number_of_intervals); |
| T total_area = T(0); |
| |
| for (std::size_t i = 0; i < number_of_intervals; ++i) |
| { |
| x = r0 + T(2) * i * h; |
| T y0 = e.value(); x += h; |
| T y1 = e.value(); x += h; |
| T y2 = e.value(); x += h; |
| total_area += h * (y0 + T(4) * y1 + y2) / T(3); |
| } |
| |
| return total_area; |
| } |
| |
| template <typename T> |
| inline T integrate(const expression<T>& e, |
| const std::string& variable_name, |
| const T& r0, const T& r1, |
| const std::size_t number_of_intervals = 1000000) |
| { |
| const symbol_table<T>& sym_table = e.get_symbol_table(); |
| |
| if (!sym_table.valid()) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| details::variable_node<T>* var = sym_table.get_variable(variable_name); |
| |
| if (var) |
| { |
| T& x = var->ref(); |
| T x_original = x; |
| T result = integrate(e,x,r0,r1,number_of_intervals); |
| x = x_original; |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| template <typename T> |
| inline T derivative(const expression<T>& e, |
| T& x, |
| const T& h = T(0.00000001)) |
| { |
| T x_init = x; |
| x = x_init + T(2) * h; |
| T y0 = e.value(); |
| x = x_init + h; |
| T y1 = e.value(); |
| x = x_init - h; |
| T y2 = e.value(); |
| x = x_init - T(2) * h; |
| T y3 = e.value(); |
| x = x_init; |
| |
| return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); |
| } |
| |
| template <typename T> |
| inline T second_derivative(const expression<T>& e, |
| T& x, |
| const T& h = T(0.00001)) |
| { |
| T y = e.value(); |
| T x_init = x; |
| x = x_init + T(2) * h; |
| T y0 = e.value(); |
| x = x_init + h; |
| T y1 = e.value(); |
| x = x_init - h; |
| T y2 = e.value(); |
| x = x_init - T(2) * h; |
| T y3 = e.value(); |
| x = x_init; |
| |
| return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); |
| } |
| |
| template <typename T> |
| inline T third_derivative(const expression<T>& e, |
| T& x, |
| const T& h = T(0.0001)) |
| { |
| T x_init = x; |
| x = x_init + T(2) * h; |
| T y0 = e.value(); |
| x = x_init + h; |
| T y1 = e.value(); |
| x = x_init - h; |
| T y2 = e.value(); |
| x = x_init - T(2) * h; |
| T y3 = e.value(); |
| x = x_init; |
| |
| return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); |
| } |
| |
| template <typename T> |
| inline T derivative(const expression<T>& e, |
| const std::string& variable_name, |
| const T& h = T(0.00000001)) |
| { |
| const symbol_table<T>& sym_table = e.get_symbol_table(); |
| |
| if (!sym_table.valid()) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| details::variable_node<T>* var = sym_table.get_variable(variable_name); |
| |
| if (var) |
| { |
| T& x = var->ref(); |
| T x_original = x; |
| T result = derivative(e,x,h); |
| x = x_original; |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| template <typename T> |
| inline T second_derivative(const expression<T>& e, |
| const std::string& variable_name, |
| const T& h = T(0.00001)) |
| { |
| const symbol_table<T>& sym_table = e.get_symbol_table(); |
| |
| if (!sym_table.valid()) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| details::variable_node<T>* var = sym_table.get_variable(variable_name); |
| |
| if (var) |
| { |
| T& x = var->ref(); |
| T x_original = x; |
| T result = second_derivative(e,x,h); |
| x = x_original; |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| template <typename T> |
| inline T third_derivative(const expression<T>& e, |
| const std::string& variable_name, |
| const T& h = T(0.0001)) |
| { |
| const symbol_table<T>& sym_table = e.get_symbol_table(); |
| |
| if (!sym_table.valid()) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| details::variable_node<T>* var = sym_table.get_variable(variable_name); |
| |
| if (var) |
| { |
| T& x = var->ref(); |
| T x_original = x; |
| T result = third_derivative(e,x,h); |
| x = x_original; |
| |
| return result; |
| } |
| else |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| /* |
| Note: The following 'compute' routines are simple helpers, |
| for quickly setting up the required pieces of code in order |
| to evaluate an expression. By virtue of how they operate |
| there will be an overhead with regards to their setup and |
| teardown and hence should not be used in time critical |
| sections of code. |
| Furthermore they only assume a small sub set of variables - no |
| string variables or user defined functions. |
| */ |
| template <typename T> |
| inline bool compute(const std::string& expression_string, T& result) |
| { |
| // No variables |
| symbol_table<T> symbol_table; |
| symbol_table.add_constants(); |
| |
| expression<T> expression; |
| parser<T> parser; |
| |
| if (parser.compile(expression_string,expression)) |
| { |
| result = expression.value(); |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| template <typename T> |
| inline bool compute(const std::string& expression_string, |
| const T& x, |
| T& result) |
| { |
| // Only 'x' |
| static const std::string x_var("x"); |
| |
| symbol_table<T> symbol_table; |
| symbol_table.add_constants(); |
| symbol_table.add_variable(x_var,x); |
| |
| expression<T> expression; |
| parser<T> parser; |
| |
| if (parser.compile(expression_string,expression)) |
| { |
| result = expression.value(); |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| template <typename T> |
| inline bool compute(const std::string& expression_string, |
| const T&x, const T& y, |
| T& result) |
| { |
| // Only 'x' and 'y' |
| static const std::string x_var("x"); |
| static const std::string y_var("y"); |
| |
| symbol_table<T> symbol_table; |
| symbol_table.add_constants(); |
| symbol_table.add_variable(x_var,x); |
| symbol_table.add_variable(y_var,y); |
| |
| expression<T> expression; |
| parser<T> parser; |
| |
| if (parser.compile(expression_string,expression)) |
| { |
| result = expression.value(); |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| template <typename T> |
| inline bool compute(const std::string& expression_string, |
| const T& x, const T& y, const T& z, |
| T& result) |
| { |
| // Only 'x', 'y' or 'z' |
| static const std::string x_var("x"); |
| static const std::string y_var("y"); |
| static const std::string z_var("z"); |
| |
| symbol_table<T> symbol_table; |
| symbol_table.add_constants(); |
| symbol_table.add_variable(x_var,x); |
| symbol_table.add_variable(y_var,y); |
| symbol_table.add_variable(z_var,z); |
| |
| expression<T> expression; |
| parser<T> parser; |
| |
| if (parser.compile(expression_string,expression)) |
| { |
| result = expression.value(); |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| template <typename T, std::size_t N> |
| class polynomial : public ifunction<T> |
| { |
| private: |
| |
| template <typename Type, std::size_t NumberOfCoefficients> |
| struct poly_impl { }; |
| |
| template <typename Type> |
| struct poly_impl <Type,12> |
| { |
| static inline T evaluate(const Type x, |
| const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, |
| const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, |
| const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,11> |
| { |
| static inline T evaluate(const Type x, |
| const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, |
| const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, |
| const Type c1, const Type c0) |
| { |
| // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,10> |
| { |
| static inline T evaluate(const Type x, |
| const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, |
| const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, |
| const Type c0) |
| { |
| // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,9> |
| { |
| static inline T evaluate(const Type x, |
| const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, |
| const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,8> |
| { |
| static inline T evaluate(const Type x, |
| const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, |
| const Type c3, const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,7> |
| { |
| static inline T evaluate(const Type x, |
| const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, |
| const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,6> |
| { |
| static inline T evaluate(const Type x, |
| const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, |
| const Type c1, const Type c0) |
| { |
| // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,5> |
| { |
| static inline T evaluate(const Type x, |
| const Type c5, const Type c4, const Type c3, const Type c2, |
| const Type c1, const Type c0) |
| { |
| // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,4> |
| { |
| static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,3> |
| { |
| static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 |
| return (((c3 * x + c2) * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,2> |
| { |
| static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) |
| { |
| // p(x) = c_2x^2 + c_1x^1 + c_0x^0 |
| return ((c2 * x + c1) * x + c0); |
| } |
| }; |
| |
| template <typename Type> |
| struct poly_impl <Type,1> |
| { |
| static inline T evaluate(const Type x, const Type c1, const Type c0) |
| { |
| // p(x) = c_1x^1 + c_0x^0 |
| return (c1 * x + c0); |
| } |
| }; |
| |
| public: |
| |
| using ifunction<T>::operator(); |
| |
| polynomial() |
| : ifunction<T>((N+2 <= 20) ? (N + 2) : std::numeric_limits<std::size_t>::max()) |
| { |
| disable_has_side_effects(*this); |
| } |
| |
| virtual ~polynomial() |
| {} |
| |
| #define poly_rtrn(NN) \ |
| return (NN != N) ? std::numeric_limits<T>::quiet_NaN() : |
| |
| inline virtual T operator()(const T& x, const T& c1, const T& c0) |
| { |
| poly_rtrn(1) poly_impl<T,1>::evaluate(x,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(2) poly_impl<T,2>::evaluate(x,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(3) poly_impl<T,3>::evaluate(x,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(4) poly_impl<T,4>::evaluate(x,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(5) poly_impl<T,5>::evaluate(x,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(6) poly_impl<T,6>::evaluate(x,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(7) poly_impl<T,7>::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(8) poly_impl<T,8>::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(9) poly_impl<T,9>::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(10) poly_impl<T,10>::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(11) poly_impl<T,11>::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) |
| { |
| poly_rtrn(12) poly_impl<T,12>::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); |
| } |
| |
| #undef poly_rtrn |
| |
| inline virtual T operator()() |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline virtual T operator()(const T&) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| |
| inline virtual T operator()(const T&, const T&) |
| { |
| return std::numeric_limits<T>::quiet_NaN(); |
| } |
| }; |
| |
| template <typename T> |
| class function_compositor |
| { |
| public: |
| |
| typedef exprtk::expression<T> expression_t; |
| typedef exprtk::symbol_table<T> symbol_table_t; |
| typedef exprtk::parser<T> parser_t; |
| typedef typename parser_t::settings_store settings_t; |
| |
| struct function |
| { |
| function() |
| {} |
| |
| function(const std::string& n) |
| : name_(n) |
| {} |
| |
| function(const std::string& name, |
| const std::string& expression) |
| : name_(name), |
| expression_(expression) |
| {} |
| |
| function(const std::string& name, |
| const std::string& expression, |
| const std::string& v0) |
| : name_(name), |
| expression_(expression) |
| { |
| v_.push_back(v0); |
| } |
| |
| function(const std::string& name, |
| const std::string& expression, |
| const std::string& v0, const std::string& v1) |
| : name_(name), |
| expression_(expression) |
| { |
| v_.push_back(v0); v_.push_back(v1); |
| } |
| |
| function(const std::string& name, |
| const std::string& expression, |
| const std::string& v0, const std::string& v1, |
| const std::string& v2) |
| : name_(name), |
| expression_(expression) |
| { |
| v_.push_back(v0); v_.push_back(v1); |
| v_.push_back(v2); |
| } |
| |
| function(const std::string& name, |
| const std::string& expression, |
| const std::string& v0, const std::string& v1, |
| const std::string& v2, const std::string& v3) |
| : name_(name), |
| expression_(expression) |
| { |
| v_.push_back(v0); v_.push_back(v1); |
| v_.push_back(v2); v_.push_back(v3); |
| } |
| |
| function(const std::string& name, |
| const std::string& expression, |
| const std::string& v0, const std::string& v1, |
| const std::string& v2, const std::string& v3, |
| const std::string& v4) |
| : name_(name), |
| expression_(expression) |
| { |
| v_.push_back(v0); v_.push_back(v1); |
| v_.push_back(v2); v_.push_back(v3); |
| v_.push_back(v4); |
| } |
| |
| inline function& name(const std::string& n) |
| { |
| name_ = n; |
| return (*this); |
| } |
| |
| inline function& expression(const std::string& e) |
| { |
| expression_ = e; |
| return (*this); |
| } |
| |
| inline function& var(const std::string& v) |
| { |
| v_.push_back(v); |
| return (*this); |
| } |
| |
| std::string name_; |
| std::string expression_; |
| std::deque<std::string> v_; |
| }; |
| |
| private: |
| |
| struct base_func : public exprtk::ifunction<T> |
| { |
| typedef const T& type; |
| typedef exprtk::ifunction<T> function_t; |
| typedef std::vector<T*> varref_t; |
| typedef std::vector<T> var_t; |
| typedef std::pair<T*,std::size_t> lvarref_t; |
| typedef std::vector<lvarref_t> lvr_vec_t; |
| |
| using exprtk::ifunction<T>::operator(); |
| |
| base_func(const std::size_t& pc = 0) |
| : exprtk::ifunction<T>(pc), |
| local_var_stack_size(0), |
| stack_depth(0) |
| { |
| v.resize(pc); |
| } |
| |
| virtual ~base_func() |
| {} |
| |
| inline void update(const T& v0) |
| { |
| (*v[0]) = v0; |
| } |
| |
| inline void update(const T& v0, const T& v1) |
| { |
| (*v[0]) = v0; (*v[1]) = v1; |
| } |
| |
| inline void update(const T& v0, const T& v1, const T& v2) |
| { |
| (*v[0]) = v0; (*v[1]) = v1; |
| (*v[2]) = v2; |
| } |
| |
| inline void update(const T& v0, const T& v1, const T& v2, const T& v3) |
| { |
| (*v[0]) = v0; (*v[1]) = v1; |
| (*v[2]) = v2; (*v[3]) = v3; |
| } |
| |
| inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) |
| { |
| (*v[0]) = v0; (*v[1]) = v1; |
| (*v[2]) = v2; (*v[3]) = v3; |
| (*v[4]) = v4; |
| } |
| |
| inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) |
| { |
| (*v[0]) = v0; (*v[1]) = v1; |
| (*v[2]) = v2; (*v[3]) = v3; |
| (*v[4]) = v4; (*v[5]) = v5; |
| } |
| |
| inline function_t& setup(expression_t& expr) |
| { |
| expression = expr; |
| |
| typedef typename expression_t::control_block::local_data_list_t ldl_t; |
| |
| ldl_t ldl = expr.local_data_list(); |
| |
| std::vector<std::size_t> index_list; |
| |
| for (std::size_t i = 0; i < ldl.size(); ++i) |
| { |
| if (ldl[i].size) |
| { |
| index_list.push_back(i); |
| } |
| } |
| |
| std::size_t input_param_count = 0; |
| |
| for (std::size_t i = 0; i < index_list.size(); ++i) |
| { |
| const std::size_t index = index_list[i]; |
| |
| if (i < (index_list.size() - v.size())) |
| { |
| lv.push_back( |
| std::make_pair( |
| reinterpret_cast<T*>(ldl[index].pointer), |
| ldl[index].size)); |
| |
| local_var_stack_size += ldl[index].size; |
| } |
| else |
| v[input_param_count++] = reinterpret_cast<T*>(ldl[index].pointer); |
| } |
| |
| clear_stack(); |
| |
| return (*this); |
| } |
| |
| inline void pre() |
| { |
| if (stack_depth++) |
| { |
| if (!v.empty()) |
| { |
| var_t var_stack(v.size(),T(0)); |
| copy(v,var_stack); |
| param_stack.push_back(var_stack); |
| } |
| |
| if (!lv.empty()) |
| { |
| var_t local_var_stack(local_var_stack_size,T(0)); |
| copy(lv,local_var_stack); |
| local_stack.push_back(local_var_stack); |
| } |
| } |
| } |
| |
| inline void post() |
| { |
| if (--stack_depth) |
| { |
| if (!v.empty()) |
| { |
| copy(param_stack.back(),v); |
| param_stack.pop_back(); |
| } |
| |
| if (!lv.empty()) |
| { |
| copy(local_stack.back(),lv); |
| local_stack.pop_back(); |
| } |
| } |
| } |
| |
| void copy(const varref_t& src_v, var_t& dest_v) |
| { |
| for (std::size_t i = 0; i < src_v.size(); ++i) |
| { |
| dest_v[i] = (*src_v[i]); |
| } |
| } |
| |
| void copy(const var_t& src_v, varref_t& dest_v) |
| { |
| for (std::size_t i = 0; i < src_v.size(); ++i) |
| { |
| (*dest_v[i]) = src_v[i]; |
| } |
| } |
| |
| void copy(const lvr_vec_t& src_v, var_t& dest_v) |
| { |
| typename var_t::iterator itr = dest_v.begin(); |
| |
| for (std::size_t i = 0; i < src_v.size(); ++i) |
| { |
| lvarref_t vr = src_v[i]; |
| |
| if (1 == vr.second) |
| *itr++ = (*vr.first); |
| else |
| { |
| std::copy(vr.first,vr.first + vr.second,itr); |
| itr += vr.second; |
| } |
| } |
| } |
| |
| void copy(const var_t& src_v, lvr_vec_t& dest_v) |
| { |
| typename var_t::const_iterator itr = src_v.begin(); |
| |
| for (std::size_t i = 0; i < src_v.size(); ++i) |
| { |
| lvarref_t vr = dest_v[i]; |
| |
| if (1 == vr.second) |
| (*vr.first) = *itr++; |
| else |
| { |
| std::copy(itr,itr + vr.second,vr.first); |
| itr += vr.second; |
| } |
| } |
| } |
| |
| inline void clear_stack() |
| { |
| for (std::size_t i = 0; i < v.size(); ++i) |
| { |
| (*v[i]) = 0; |
| } |
| } |
| |
| inline virtual T value(expression_t& e) |
| { |
| return e.value(); |
| } |
| |
| expression_t expression; |
| varref_t v; |
| lvr_vec_t lv; |
| std::size_t local_var_stack_size; |
| std::size_t stack_depth; |
| std::deque<var_t> param_stack; |
| std::deque<var_t> local_stack; |
| }; |
| |
| typedef std::map<std::string,base_func*> funcparam_t; |
| |
| struct func_0param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_0param() : base_func(0) {} |
| |
| inline T operator()() |
| { |
| return this->value(base_func::expression); |
| } |
| }; |
| |
| typedef const T& type; |
| |
| template <typename BaseFuncType> |
| struct scoped_bft |
| { |
| scoped_bft(BaseFuncType& bft) : bft_(bft) { bft_.pre (); } |
| ~scoped_bft() { bft_.post(); } |
| |
| BaseFuncType& bft_; |
| |
| private: |
| |
| scoped_bft(scoped_bft&); |
| scoped_bft& operator=(scoped_bft&); |
| }; |
| |
| struct func_1param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_1param() : base_func(1) {} |
| |
| inline T operator()(type v0) |
| { |
| scoped_bft<func_1param> sb(*this); |
| base_func::update(v0); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| struct func_2param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_2param() : base_func(2) {} |
| |
| inline T operator()(type v0, type v1) |
| { |
| scoped_bft<func_2param> sb(*this); |
| base_func::update(v0,v1); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| struct func_3param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_3param() : base_func(3) {} |
| |
| inline T operator()(type v0, type v1, type v2) |
| { |
| scoped_bft<func_3param> sb(*this); |
| base_func::update(v0,v1,v2); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| struct func_4param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_4param() : base_func(4) {} |
| |
| inline T operator()(type v0, type v1, type v2, type v3) |
| { |
| scoped_bft<func_4param> sb(*this); |
| base_func::update(v0,v1,v2,v3); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| struct func_5param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_5param() : base_func(5) {} |
| |
| inline T operator()(type v0, type v1, type v2, type v3, type v4) |
| { |
| scoped_bft<func_5param> sb(*this); |
| base_func::update(v0,v1,v2,v3,v4); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| struct func_6param : public base_func |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| func_6param() : base_func(6) {} |
| |
| inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) |
| { |
| scoped_bft<func_6param> sb(*this); |
| base_func::update(v0,v1,v2,v3,v4,v5); |
| T result = this->value(base_func::expression); |
| |
| return result; |
| } |
| }; |
| |
| static T return_value(expression_t& e) |
| { |
| typedef exprtk::results_context<T> results_context_t; |
| typedef typename results_context_t::type_store_t type_t; |
| typedef typename type_t::scalar_view scalar_t; |
| |
| T result = e.value(); |
| |
| if (e.return_invoked()) |
| { |
| // Due to the post compilation checks, it can be safely |
| // assumed that there will be at least one parameter |
| // and that the first parameter will always be scalar. |
| return scalar_t(e.results()[0])(); |
| } |
| |
| return result; |
| } |
| |
| #define def_fp_retval(N) \ |
| struct func_##N##param_retval : public func_##N##param \ |
| { \ |
| inline T value(expression_t& e) \ |
| { \ |
| return return_value(e); \ |
| } \ |
| }; \ |
| |
| def_fp_retval(0) |
| def_fp_retval(1) |
| def_fp_retval(2) |
| def_fp_retval(3) |
| def_fp_retval(4) |
| def_fp_retval(5) |
| def_fp_retval(6) |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| inline bool add(const std::string& name, |
| const std::string& expression, |
| const Sequence<std::string,Allocator>& var_list, |
| const bool override = false) |
| { |
| const std::size_t n = var_list.size(); |
| |
| typename std::map<std::string,expression_t>::iterator itr = expr_map_.find(name); |
| |
| if (expr_map_.end() != itr) |
| { |
| if (!override) |
| { |
| exprtk_debug(("Compositor error(add): function '%s' already defined\n", |
| name.c_str())); |
| |
| return false; |
| } |
| |
| remove(name, var_list.size()); |
| } |
| |
| if (compile_expression(name,expression,var_list)) |
| { |
| fp_map_[n][name]->setup(expr_map_[name]); |
| |
| return true; |
| } |
| else |
| { |
| exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", |
| name.c_str())); |
| |
| return false; |
| } |
| } |
| |
| public: |
| |
| function_compositor() |
| : parser_(settings_t::compile_all_opts + |
| settings_t::e_disable_zero_return), |
| fp_map_(7) |
| {} |
| |
| function_compositor(const symbol_table_t& st) |
| : symbol_table_(st), |
| parser_(settings_t::compile_all_opts + |
| settings_t::e_disable_zero_return), |
| fp_map_(7) |
| {} |
| |
| ~function_compositor() |
| { |
| clear(); |
| } |
| |
| inline symbol_table_t& symbol_table() |
| { |
| return symbol_table_; |
| } |
| |
| inline void add_auxiliary_symtab(symbol_table_t& symtab) |
| { |
| auxiliary_symtab_list_.push_back(&symtab); |
| } |
| |
| void clear() |
| { |
| symbol_table_.clear(); |
| expr_map_ .clear(); |
| |
| for (std::size_t i = 0; i < fp_map_.size(); ++i) |
| { |
| typename funcparam_t::iterator itr = fp_map_[i].begin(); |
| typename funcparam_t::iterator end = fp_map_[i].end (); |
| |
| while (itr != end) |
| { |
| delete itr->second; |
| ++itr; |
| } |
| |
| fp_map_[i].clear(); |
| } |
| } |
| |
| inline bool add(const function& f, const bool override = false) |
| { |
| return add(f.name_,f.expression_,f.v_,override); |
| } |
| |
| private: |
| |
| template <typename Allocator, |
| template <typename,typename> class Sequence> |
| bool compile_expression(const std::string& name, |
| const std::string& expression, |
| const Sequence<std::string,Allocator>& input_var_list, |
| bool return_present = false) |
| { |
| expression_t compiled_expression; |
| symbol_table_t local_symbol_table; |
| |
| local_symbol_table.load_from(symbol_table_); |
| local_symbol_table.add_constants(); |
| |
| if (!valid(name,input_var_list.size())) |
| return false; |
| |
| if (!forward(name, |
| input_var_list.size(), |
| local_symbol_table, |
| return_present)) |
| return false; |
| |
| compiled_expression.register_symbol_table(local_symbol_table); |
| |
| for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) |
| { |
| compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); |
| } |
| |
| std::string mod_expression; |
| |
| for (std::size_t i = 0; i < input_var_list.size(); ++i) |
| { |
| mod_expression += " var " + input_var_list[i] + "{};\n"; |
| } |
| |
| if ( |
| ('{' == details::front(expression)) && |
| ('}' == details::back (expression)) |
| ) |
| mod_expression += "~" + expression + ";"; |
| else |
| mod_expression += "~{" + expression + "};"; |
| |
| if (!parser_.compile(mod_expression,compiled_expression)) |
| { |
| exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); |
| exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); |
| |
| remove(name,input_var_list.size()); |
| |
| return false; |
| } |
| |
| if (!return_present && parser_.dec().return_present()) |
| { |
| remove(name,input_var_list.size()); |
| |
| return compile_expression(name,expression,input_var_list,true); |
| } |
| |
| // Make sure every return point has a scalar as its first parameter |
| if (parser_.dec().return_present()) |
| { |
| typedef std::vector<std::string> str_list_t; |
| |
| str_list_t ret_param_list = parser_.dec().return_param_type_list(); |
| |
| for (std::size_t i = 0; i < ret_param_list.size(); ++i) |
| { |
| const std::string& params = ret_param_list[i]; |
| |
| if (params.empty() || ('T' != params[0])) |
| { |
| exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", |
| name.c_str())); |
| |
| remove(name,input_var_list.size()); |
| |
| return false; |
| } |
| } |
| } |
| |
| expr_map_[name] = compiled_expression; |
| |
| exprtk::ifunction<T>& ifunc = (*(fp_map_[input_var_list.size()])[name]); |
| |
| if (symbol_table_.add_function(name,ifunc)) |
| return true; |
| else |
| { |
| exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", |
| name.c_str())); |
| return false; |
| } |
| } |
| |
| inline bool symbol_used(const std::string& symbol) const |
| { |
| return ( |
| symbol_table_.is_variable (symbol) || |
| symbol_table_.is_stringvar (symbol) || |
| symbol_table_.is_function (symbol) || |
| symbol_table_.is_vector (symbol) || |
| symbol_table_.is_vararg_function(symbol) |
| ); |
| } |
| |
| inline bool valid(const std::string& name, |
| const std::size_t& arg_count) const |
| { |
| if (arg_count > 6) |
| return false; |
| else if (symbol_used(name)) |
| return false; |
| else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) |
| return false; |
| else |
| return true; |
| } |
| |
| inline bool forward(const std::string& name, |
| const std::size_t& arg_count, |
| symbol_table_t& sym_table, |
| const bool ret_present = false) |
| { |
| switch (arg_count) |
| { |
| #define case_stmt(N) \ |
| case N : (fp_map_[arg_count])[name] = \ |
| (!ret_present) ? static_cast<base_func*> \ |
| (new func_##N##param) : \ |
| static_cast<base_func*> \ |
| (new func_##N##param_retval) ; \ |
| break; \ |
| |
| case_stmt(0) case_stmt(1) case_stmt(2) |
| case_stmt(3) case_stmt(4) case_stmt(5) |
| case_stmt(6) |
| #undef case_stmt |
| } |
| |
| exprtk::ifunction<T>& ifunc = (*(fp_map_[arg_count])[name]); |
| |
| return sym_table.add_function(name,ifunc); |
| } |
| |
| inline void remove(const std::string& name, const std::size_t& arg_count) |
| { |
| if (arg_count > 6) |
| return; |
| |
| typename std::map<std::string,expression_t>::iterator em_itr = expr_map_.find(name); |
| |
| if (expr_map_.end() != em_itr) |
| { |
| expr_map_.erase(em_itr); |
| } |
| |
| typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); |
| |
| if (fp_map_[arg_count].end() != fp_itr) |
| { |
| delete fp_itr->second; |
| fp_map_[arg_count].erase(fp_itr); |
| } |
| |
| symbol_table_.remove_function(name); |
| } |
| |
| private: |
| |
| symbol_table_t symbol_table_; |
| parser_t parser_; |
| std::map<std::string,expression_t> expr_map_; |
| std::vector<funcparam_t> fp_map_; |
| std::vector<symbol_table_t*> auxiliary_symtab_list_; |
| }; |
| |
| template <typename T> |
| inline bool pgo_primer() |
| { |
| static const std::string expression_list[] |
| = { |
| "(y + x)", |
| "2 * (y + x)", |
| "(2 * y + 2 * x)", |
| "(y + x / y) * (x - y / x)", |
| "x / ((x + y) * (x - y)) / y", |
| "1 - ((x * y) + (y / x)) - 3", |
| "sin(2 * x) + cos(pi / y)", |
| "1 - sin(2 * x) + cos(pi / y)", |
| "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", |
| "(x^2 / sin(2 * pi / y)) -x / 2", |
| "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", |
| "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", |
| "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", |
| "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", |
| "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", |
| "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", |
| "(yy + xx)", |
| "2 * (yy + xx)", |
| "(2 * yy + 2 * xx)", |
| "(yy + xx / yy) * (xx - yy / xx)", |
| "xx / ((xx + yy) * (xx - yy)) / yy", |
| "1 - ((xx * yy) + (yy / xx)) - 3", |
| "sin(2 * xx) + cos(pi / yy)", |
| "1 - sin(2 * xx) + cos(pi / yy)", |
| "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", |
| "(xx^2 / sin(2 * pi / yy)) -xx / 2", |
| "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", |
| "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", |
| "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", |
| "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", |
| "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", |
| "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", |
| "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", |
| "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", |
| "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", |
| "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", |
| "(x + 2) * 3", "x + (2 * 3)", |
| "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", |
| "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", |
| "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", |
| "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", |
| "2 + (x * (y / 3))", "x + (2 * (3 / y))", |
| "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", |
| "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", |
| "x + ((2 * 3) / y)", "(((x + y) * z) / w)", |
| "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", |
| "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", |
| "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", |
| "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", |
| "((x + (2 * 3)) / y)", |
| "(xx + yy) * zz", "xx + (yy * zz)", |
| "(xx + yy) * 7", "xx + (yy * 7)", |
| "(xx + 7) * yy", "xx + (7 * yy)", |
| "(7 + xx) * yy", "7 + (xx * yy)", |
| "(2 + x) * 3", "2 + (x * 3)", |
| "(2 + 3) * x", "2 + (3 * x)", |
| "(x + 2) * 3", "x + (2 * 3)", |
| "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", |
| "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", |
| "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", |
| "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", |
| "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", |
| "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", |
| "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", |
| "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", |
| "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", |
| "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", |
| "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", |
| "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", |
| "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", |
| "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", |
| "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", |
| "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", |
| "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", |
| "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", |
| "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", |
| "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", |
| "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", |
| "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", |
| "((xx + (2 * 3)) / yy)" |
| }; |
| static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); |
| |
| T x = T(0); |
| T y = T(0); |
| T z = T(0); |
| T w = T(0); |
| T xx = T(0); |
| T yy = T(0); |
| T zz = T(0); |
| T ww = T(0); |
| |
| exprtk::symbol_table<T> symbol_table; |
| symbol_table.add_constants(); |
| symbol_table.add_variable( "x", x); |
| symbol_table.add_variable( "y", y); |
| symbol_table.add_variable( "z", z); |
| symbol_table.add_variable( "w", w); |
| symbol_table.add_variable("xx",xx); |
| symbol_table.add_variable("yy",yy); |
| symbol_table.add_variable("zz",zz); |
| symbol_table.add_variable("ww",ww); |
| |
| typedef typename std::deque<exprtk::expression<T> > expr_list_t; |
| expr_list_t expr_list; |
| |
| const std::size_t rounds = 50; |
| |
| { |
| for (std::size_t r = 0; r < rounds; ++r) |
| { |
| expr_list.clear(); |
| exprtk::parser<T> parser; |
| |
| for (std::size_t i = 0; i < expression_list_size; ++i) |
| { |
| exprtk::expression<T> expression; |
| expression.register_symbol_table(symbol_table); |
| |
| if (!parser.compile(expression_list[i],expression)) |
| { |
| return false; |
| } |
| |
| expr_list.push_back(expression); |
| } |
| } |
| } |
| |
| struct execute |
| { |
| static inline T process(T& x, T& y, expression<T>& expression) |
| { |
| static const T lower_bound = T(-20); |
| static const T upper_bound = T(+20); |
| |
| T delta = T(0.1); |
| T total = T(0); |
| |
| for (x = lower_bound; x <= upper_bound; x += delta) |
| { |
| for (y = lower_bound; y <= upper_bound; y += delta) |
| { |
| total += expression.value(); |
| } |
| } |
| |
| return total; |
| } |
| }; |
| |
| for (std::size_t i = 0; i < expr_list.size(); ++i) |
| { |
| execute::process( x, y, expr_list[i]); |
| execute::process(xx, yy, expr_list[i]); |
| } |
| |
| { |
| for (std::size_t i = 0; i < 10000; ++i) |
| { |
| T v = T(123.456 + i); |
| |
| if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 1>::result(v),details::numeric::pow(v,T( 1))))) |
| return false; |
| |
| #define else_stmt(N) \ |
| else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,N>::result(v),details::numeric::pow(v,T(N))))) \ |
| return false; \ |
| |
| else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) |
| else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) |
| else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) |
| else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) |
| else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) |
| else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) |
| else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) |
| else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) |
| else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) |
| else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) |
| else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) |
| else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) |
| else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) |
| else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) |
| else_stmt(58) else_stmt(59) else_stmt(60) |
| } |
| } |
| |
| return true; |
| } |
| } |
| |
| #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) |
| # ifndef NOMINMAX |
| # define NOMINMAX |
| # endif |
| # ifndef WIN32_LEAN_AND_MEAN |
| # define WIN32_LEAN_AND_MEAN |
| # endif |
| # include <windows.h> |
| # include <ctime> |
| #else |
| # include <ctime> |
| # include <sys/time.h> |
| # include <sys/types.h> |
| #endif |
| |
| namespace exprtk |
| { |
| class timer |
| { |
| public: |
| |
| #if defined(_WIN32) || defined(__WIN32__) || defined(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<unsigned long long int>::max(); |
| } |
| else |
| return std::numeric_limits<unsigned long long int>::max(); |
| } |
| |
| inline double time() const |
| { |
| return usec_time() * 0.000001; |
| } |
| |
| #endif |
| |
| inline bool in_use() const |
| { |
| return in_use_; |
| } |
| |
| private: |
| |
| bool in_use_; |
| |
| #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) |
| LARGE_INTEGER start_time_; |
| LARGE_INTEGER stop_time_; |
| LARGE_INTEGER clock_frequency_; |
| #else |
| struct timeval start_time_; |
| struct timeval stop_time_; |
| #endif |
| }; |
| |
| } // namespace exprtk |
| |
| #ifndef exprtk_disable_rtl_io |
| namespace exprtk |
| { |
| namespace rtl { namespace io { namespace details |
| { |
| template <typename T> |
| inline void print_type(const std::string& fmt, |
| const T v, |
| exprtk::details::numeric::details::real_type_tag) |
| { |
| printf(fmt.c_str(),v); |
| } |
| |
| template <typename T> |
| struct print_impl |
| { |
| typedef typename igeneric_function<T>::generic_type generic_type; |
| typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| typedef typename generic_type::string_view string_t; |
| typedef typename exprtk::details::numeric::details::number_type<T>::type num_type; |
| |
| static void process(const std::string& scalar_format, parameter_list_t parameters) |
| { |
| for (std::size_t i = 0; i < parameters.size(); ++i) |
| { |
| generic_type& gt = parameters[i]; |
| |
| switch (gt.type) |
| { |
| case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); |
| break; |
| |
| case generic_type::e_vector : print(scalar_format,vector_t(gt)); |
| break; |
| |
| case generic_type::e_string : print(string_t(gt)); |
| break; |
| |
| default : continue; |
| } |
| } |
| } |
| |
| static inline void print(const std::string& scalar_format, const scalar_t& s) |
| { |
| print_type(scalar_format,s(),num_type()); |
| } |
| |
| static inline void print(const std::string& scalar_format, const vector_t& v) |
| { |
| for (std::size_t i = 0; i < v.size(); ++i) |
| { |
| print_type(scalar_format,v[i],num_type()); |
| |
| if ((i + 1) < v.size()) |
| printf(" "); |
| } |
| } |
| |
| static inline void print(const string_t& s) |
| { |
| printf("%s",to_str(s).c_str()); |
| } |
| }; |
| |
| } // namespace exprtk::rtl::io::details |
| |
| template <typename T> |
| struct print : public exprtk::igeneric_function<T> |
| { |
| typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| print(const std::string& scalar_format = "%10.5f") |
| : scalar_format_(scalar_format) |
| { |
| exprtk::enable_zero_parameters(*this); |
| } |
| |
| inline T operator()(parameter_list_t parameters) |
| { |
| details::print_impl<T>::process(scalar_format_,parameters); |
| return T(0); |
| } |
| |
| std::string scalar_format_; |
| }; |
| |
| template <typename T> |
| struct println : public exprtk::igeneric_function<T> |
| { |
| typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| println(const std::string& scalar_format = "%10.5f") |
| : scalar_format_(scalar_format) |
| { |
| exprtk::enable_zero_parameters(*this); |
| } |
| |
| inline T operator()(parameter_list_t parameters) |
| { |
| details::print_impl<T>::process(scalar_format_,parameters); |
| printf("\n"); |
| return T(0); |
| } |
| |
| std::string scalar_format_; |
| }; |
| |
| template <typename T> |
| struct package |
| { |
| print <T> p; |
| println<T> pl; |
| |
| bool register_package(exprtk::symbol_table<T>& symtab) |
| { |
| if (!symtab.add_function("print" ,p)) |
| return false; |
| else if (!symtab.add_function("println" ,pl)) |
| return false; |
| else |
| return true; |
| } |
| }; |
| |
| } // namespace exprtk::rtl::io |
| } // namespace exprtk::rtl |
| } // namespace exprtk |
| #endif |
| |
| #ifndef exprtk_disable_rtl_io_file |
| #include <fstream> |
| namespace exprtk |
| { |
| namespace rtl { namespace io { namespace file { namespace details |
| { |
| enum file_mode |
| { |
| e_error = 0, |
| e_read = 1, |
| e_write = 2, |
| e_rdwrt = 4 |
| }; |
| |
| struct file_descriptor |
| { |
| file_descriptor(const std::string& fname, const std::string& access) |
| : stream_ptr(0), |
| mode(get_file_mode(access)), |
| file_name(fname) |
| {} |
| |
| void* stream_ptr; |
| file_mode mode; |
| std::string file_name; |
| |
| bool open() |
| { |
| if (e_read == mode) |
| { |
| std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); |
| |
| if (!(*stream)) |
| { |
| file_name.clear(); |
| delete stream; |
| |
| return false; |
| } |
| else |
| stream_ptr = stream; |
| |
| return true; |
| } |
| else if (e_write == mode) |
| { |
| std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); |
| |
| if (!(*stream)) |
| { |
| file_name.clear(); |
| delete stream; |
| |
| return false; |
| } |
| else |
| stream_ptr = stream; |
| |
| return true; |
| } |
| else if (e_rdwrt == mode) |
| { |
| std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); |
| |
| if (!(*stream)) |
| { |
| file_name.clear(); |
| delete stream; |
| |
| return false; |
| } |
| else |
| stream_ptr = stream; |
| |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| template <typename Stream, typename Ptr> |
| void close(Ptr& p) |
| { |
| Stream* stream = reinterpret_cast<Stream*>(p); |
| stream->close(); |
| delete stream; |
| p = reinterpret_cast<Ptr>(0); |
| } |
| |
| bool close() |
| { |
| switch (mode) |
| { |
| case e_read : close<std::ifstream>(stream_ptr); |
| break; |
| |
| case e_write : close<std::ofstream>(stream_ptr); |
| break; |
| |
| case e_rdwrt : close<std::fstream> (stream_ptr); |
| break; |
| |
| default : return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename View> |
| bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) |
| { |
| switch (mode) |
| { |
| case e_write : reinterpret_cast<std::ofstream*>(stream_ptr)-> |
| write(reinterpret_cast<const char*>(view.begin() + offset), amount * sizeof(typename View::value_t)); |
| break; |
| |
| case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)-> |
| write(reinterpret_cast<const char*>(view.begin() + offset) , amount * sizeof(typename View::value_t)); |
| break; |
| |
| default : return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename View> |
| bool read(View& view, const std::size_t amount, const std::size_t offset = 0) |
| { |
| switch (mode) |
| { |
| case e_read : reinterpret_cast<std::ifstream*>(stream_ptr)-> |
| read(reinterpret_cast<char*>(view.begin() + offset), amount * sizeof(typename View::value_t)); |
| break; |
| |
| case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)-> |
| read(reinterpret_cast<char*>(view.begin() + offset) , amount * sizeof(typename View::value_t)); |
| break; |
| |
| default : return false; |
| } |
| |
| return true; |
| } |
| |
| bool getline(std::string& s) |
| { |
| switch (mode) |
| { |
| case e_read : return (!!std::getline(*reinterpret_cast<std::ifstream*>(stream_ptr),s)); |
| case e_rdwrt : return (!!std::getline(*reinterpret_cast<std::fstream* >(stream_ptr),s)); |
| default : return false; |
| } |
| } |
| |
| bool eof() |
| { |
| switch (mode) |
| { |
| case e_read : return reinterpret_cast<std::ifstream*>(stream_ptr)->eof(); |
| case e_write : return reinterpret_cast<std::ofstream*>(stream_ptr)->eof(); |
| case e_rdwrt : return reinterpret_cast<std::fstream* >(stream_ptr)->eof(); |
| default : return true; |
| } |
| } |
| |
| file_mode get_file_mode(const std::string& access) |
| { |
| std::size_t w_cnt = 0; |
| std::size_t r_cnt = 0; |
| |
| for (std::size_t i = 0; i < access.size(); ++i) |
| { |
| switch (std::tolower(access[i])) |
| { |
| case 'r' : r_cnt++; break; |
| case 'w' : w_cnt++; break; |
| } |
| } |
| |
| if ((0 == r_cnt) && (0 == w_cnt)) |
| return e_error; |
| else if ((r_cnt > 1) || (w_cnt > 1)) |
| return e_error; |
| else if ((1 == r_cnt) && (1 == w_cnt)) |
| return e_rdwrt; |
| else if (1 == r_cnt) |
| return e_read; |
| else |
| return e_write; |
| } |
| }; |
| |
| template <typename T> |
| file_descriptor* make_handle(T v) |
| { |
| file_descriptor* fd = reinterpret_cast<file_descriptor*>(0); |
| |
| std::memcpy(reinterpret_cast<char*>(&fd), |
| reinterpret_cast<const char*>(&v), |
| sizeof(fd)); |
| return fd; |
| } |
| |
| template <typename T> |
| void perform_check() |
| { |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable: 4127) |
| #endif |
| if (sizeof(T) < sizeof(void*)) |
| { |
| throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); |
| } |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } |
| } // namespace exprtk::rtl::io::file::details |
| |
| template <typename T> |
| class open : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::string_view string_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| open() |
| : exprtk::igeneric_function<T>("S|SS") |
| { details::perform_check<T>(); } |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| std::string file_name; |
| std::string access; |
| |
| file_name = to_str(string_t(parameters[0])); |
| |
| if (file_name.empty()) |
| return T(0); |
| |
| if (0 == ps_index) |
| access = "r"; |
| else if (0 == string_t(parameters[1]).size()) |
| return T(0); |
| else |
| access = to_str(string_t(parameters[1])); |
| |
| details::file_descriptor* fd = new details::file_descriptor(file_name,access); |
| |
| if (fd->open()) |
| { |
| T t = T(0); |
| |
| std::memcpy(reinterpret_cast<char*>(&t), |
| reinterpret_cast<char*>(&fd), |
| sizeof(fd)); |
| return t; |
| } |
| else |
| { |
| delete fd; |
| return T(0); |
| } |
| } |
| }; |
| |
| template <typename T> |
| struct close : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| close() |
| : exprtk::ifunction<T>(1) |
| { details::perform_check<T>(); } |
| |
| inline T operator()(const T& v) |
| { |
| details::file_descriptor* fd = details::make_handle(v); |
| |
| if (!fd->close()) |
| return T(0); |
| |
| delete fd; |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class write : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::string_view string_t; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| write() |
| : igfun_t("TS|TST|TV|TVT") |
| { details::perform_check<T>(); } |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); |
| |
| std::size_t amount = 0; |
| |
| switch (ps_index) |
| { |
| case 0 : { |
| string_t buffer(parameters[1]); |
| amount = buffer.size(); |
| return T(fd->write(buffer,amount) ? 1 : 0); |
| } |
| |
| case 1 : { |
| string_t buffer(parameters[1]); |
| amount = std::min(buffer.size(), |
| static_cast<std::size_t>(scalar_t(parameters[2])())); |
| return T(fd->write(buffer,amount) ? 1 : 0); |
| } |
| |
| case 2 : { |
| vector_t vec(parameters[1]); |
| amount = vec.size(); |
| return T(fd->write(vec,amount) ? 1 : 0); |
| } |
| |
| case 3 : { |
| vector_t vec(parameters[1]); |
| amount = std::min(vec.size(), |
| static_cast<std::size_t>(scalar_t(parameters[2])())); |
| return T(fd->write(vec,amount) ? 1 : 0); |
| } |
| } |
| |
| return T(0); |
| } |
| }; |
| |
| template <typename T> |
| class read : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::string_view string_t; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| read() |
| : igfun_t("TS|TST|TV|TVT") |
| { details::perform_check<T>(); } |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); |
| |
| std::size_t amount = 0; |
| |
| switch (ps_index) |
| { |
| case 0 : { |
| string_t buffer(parameters[1]); |
| amount = buffer.size(); |
| return T(fd->read(buffer,amount) ? 1 : 0); |
| } |
| |
| case 1 : { |
| string_t buffer(parameters[1]); |
| amount = std::min(buffer.size(), |
| static_cast<std::size_t>(scalar_t(parameters[2])())); |
| return T(fd->read(buffer,amount) ? 1 : 0); |
| } |
| |
| case 2 : { |
| vector_t vec(parameters[1]); |
| amount = vec.size(); |
| return T(fd->read(vec,amount) ? 1 : 0); |
| } |
| |
| case 3 : { |
| vector_t vec(parameters[1]); |
| amount = std::min(vec.size(), |
| static_cast<std::size_t>(scalar_t(parameters[2])())); |
| return T(fd->read(vec,amount) ? 1 : 0); |
| } |
| } |
| |
| return T(0); |
| } |
| }; |
| |
| template <typename T> |
| class getline : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::string_view string_t; |
| typedef typename generic_type::scalar_view scalar_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| getline() |
| : igfun_t("T",igfun_t::e_rtrn_string) |
| { details::perform_check<T>(); } |
| |
| inline T operator()(std::string& result, |
| parameter_list_t parameters) |
| { |
| details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); |
| return T(fd->getline(result) ? 1 : 0); |
| } |
| }; |
| |
| template <typename T> |
| struct eof : public exprtk::ifunction<T> |
| { |
| using exprtk::ifunction<T>::operator(); |
| |
| eof() |
| : exprtk::ifunction<T>(1) |
| { details::perform_check<T>(); } |
| |
| inline T operator()(const T& v) |
| { |
| details::file_descriptor* fd = details::make_handle(v); |
| |
| return (fd->eof() ? T(1) : T(0)); |
| } |
| }; |
| |
| template <typename T> |
| struct package |
| { |
| open <T> o; |
| close <T> c; |
| write <T> w; |
| read <T> r; |
| getline<T> g; |
| eof <T> e; |
| |
| bool register_package(exprtk::symbol_table<T>& symtab) |
| { |
| if (!symtab.add_function("open" ,o)) |
| return false; |
| else if (!symtab.add_function("close" ,c)) |
| return false; |
| else if (!symtab.add_function("write" ,w)) |
| return false; |
| else if (!symtab.add_function("read" ,r)) |
| return false; |
| else if (!symtab.add_function("getline",g)) |
| return false; |
| else if (!symtab.add_function("eof" ,e)) |
| return false; |
| else |
| return true; |
| } |
| }; |
| |
| } // namespace exprtk::rtl::io::file |
| } // namespace exprtk::rtl::io |
| } // namespace exprtk::rtl |
| } // namespace exprtk |
| #endif |
| |
| #ifndef exprtk_disable_rtl_vecops |
| namespace exprtk |
| { |
| namespace rtl { namespace vecops { |
| |
| namespace helper |
| { |
| template <typename Vector> |
| inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) |
| { |
| if (r0 > (v.size() - 1)) |
| return true; |
| else if (r1 > (v.size() - 1)) |
| return true; |
| else if (r1 < r0) |
| return true; |
| else |
| return false; |
| } |
| |
| template <typename T> |
| struct load_vector_range |
| { |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| static inline bool process(parameter_list_t& parameters, |
| std::size_t& r0, std::size_t& r1, |
| const std::size_t& r0_prmidx, |
| const std::size_t& r1_prmidx, |
| const std::size_t vec_idx = 0) |
| { |
| if (r0_prmidx >= parameters.size()) |
| return false; |
| |
| if (r1_prmidx >= parameters.size()) |
| return false; |
| |
| if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) |
| return false; |
| |
| if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) |
| return false; |
| |
| return !invalid_range(vector_t(parameters[vec_idx]),r0,r1); |
| } |
| }; |
| } |
| |
| namespace details |
| { |
| template <typename T> |
| inline void kahan_sum(T& sum, T& error, T v) |
| { |
| T x = v - error; |
| T y = sum + x; |
| error = (y - sum) - x; |
| sum = y; |
| } |
| |
| } // namespace exprtk::rtl::details |
| |
| template <typename T> |
| class all_true : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| all_true() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| const vector_t& vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| if (vec[i] == T(0)) |
| { |
| return T(0); |
| } |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class all_false : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| all_false() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| const vector_t& vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| if (vec[i] != T(0)) |
| { |
| return T(0); |
| } |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class any_true : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| any_true() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| const vector_t& vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| if (vec[i] != T(0)) |
| { |
| return T(1); |
| } |
| } |
| |
| return T(0); |
| } |
| }; |
| |
| template <typename T> |
| class any_false : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| any_false() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| const vector_t& vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| if (vec[i] == T(0)) |
| { |
| return T(1); |
| } |
| } |
| |
| return T(0); |
| } |
| }; |
| |
| template <typename T> |
| class count : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| count() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| const vector_t& vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| std::size_t cnt = 0; |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| if (vec[i] != T(0)) ++cnt; |
| } |
| |
| return T(cnt); |
| } |
| }; |
| |
| template <typename T> |
| class copy : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| copy() |
| : exprtk::igeneric_function<T>("VV|VTTVTT") |
| /* |
| Overloads: |
| 0. VV - x(vector), y(vector) |
| 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[0]); |
| vector_t y(parameters[(0 == ps_index) ? 1 : 3]); |
| |
| std::size_t xr0 = 0; |
| std::size_t xr1 = x.size() - 1; |
| |
| std::size_t yr0 = 0; |
| std::size_t yr1 = y.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,xr0,xr1,1,2,0)) |
| return T(0); |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,yr0,yr1,4,5,3)) |
| return T(0); |
| |
| const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); |
| |
| std::copy(x.begin() + xr0, x.begin() + xr0 + n, y.begin() + yr0); |
| |
| return T(n); |
| } |
| }; |
| |
| template <typename T> |
| class rol : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| rol() |
| : exprtk::igeneric_function<T>("VT|VTTT") |
| /* |
| Overloads: |
| 0. VT - vector, N |
| 1. VTTT - vector, N, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t n = 0; |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if (!scalar_t(parameters[1]).to_uint(n)) |
| return T(0); |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return T(0); |
| |
| std::size_t dist = r1 - r0 + 1; |
| std::size_t shift = n % dist; |
| |
| std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class ror : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| ror() |
| : exprtk::igeneric_function<T>("VT|VTTT") |
| /* |
| Overloads: |
| 0. VT - vector, N |
| 1. VTTT - vector, N, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t n = 0; |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if (!scalar_t(parameters[1]).to_uint(n)) |
| return T(0); |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return T(0); |
| |
| std::size_t dist = r1 - r0 + 1; |
| std::size_t shift = (dist - (n % dist)) % dist; |
| |
| std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class shift_left : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| shift_left() |
| : exprtk::igeneric_function<T>("VT|VTTT") |
| /* |
| Overloads: |
| 0. VT - vector, N |
| 1. VTTT - vector, N, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t n = 0; |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if (!scalar_t(parameters[1]).to_uint(n)) |
| return T(0); |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return T(0); |
| |
| std::size_t dist = r1 - r0 + 1; |
| |
| if (n > dist) |
| return T(0); |
| |
| std::rotate(vec.begin() + r0, vec.begin() + r0 + n, vec.begin() + r1 + 1); |
| |
| for (std::size_t i = r1 - n + 1; i <= r1; ++i) |
| { |
| vec[i] = T(0); |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class shift_right : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| shift_right() |
| : exprtk::igeneric_function<T>("VT|VTTT") |
| /* |
| Overloads: |
| 0. VT - vector, N |
| 1. VTTT - vector, N, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t n = 0; |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if (!scalar_t(parameters[1]).to_uint(n)) |
| return T(0); |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return T(0); |
| |
| std::size_t dist = r1 - r0 + 1; |
| |
| if (n > dist) |
| return T(0); |
| |
| std::size_t shift = (dist - (n % dist)) % dist; |
| |
| std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); |
| |
| for (std::size_t i = r0; i < r0 + n; ++i) |
| { |
| vec[i] = T(0); |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class sort : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::string_view string_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| sort() |
| : exprtk::igeneric_function<T>("V|VTT|VS|VSTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| 2. VS - vector, string |
| 3. VSTT - vector, string, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return T(0); |
| if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return T(0); |
| |
| bool ascending = true; |
| |
| if ((2 == ps_index) || (3 == ps_index)) |
| { |
| if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) |
| ascending = true; |
| else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) |
| ascending = false; |
| else |
| return T(0); |
| } |
| |
| if (ascending) |
| std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::less<T> ()); |
| else |
| std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::greater<T>()); |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class nthelement : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| nthelement() |
| : exprtk::igeneric_function<T>("VT|VTTT") |
| /* |
| Overloads: |
| 0. VT - vector, nth-element |
| 1. VTTT - vector, nth-element, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t n = 0; |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if (!scalar_t(parameters[1]).to_uint(n)) |
| return T(0); |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class iota : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| iota() |
| : exprtk::igeneric_function<T>("VT|VTT|VTTT|VTTTT") |
| /* |
| Overloads: |
| 0. VT - vector, increment |
| 1. VTT - vector, increment, base |
| 2. VTTTT - vector, increment, r0, r1 |
| 3. VTTTT - vector, increment, base, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| T increment = scalar_t(parameters[1])(); |
| T base = ((1 == ps_index) || (3 == ps_index))? scalar_t(parameters[2])() : T(0); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((2 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else |
| { |
| long long j = 0; |
| |
| for (std::size_t i = r0; i <= r1; ++i, ++j) |
| { |
| vec[i] = base + (increment * j); |
| } |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class sumk : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| sumk() |
| : exprtk::igeneric_function<T>("V|VTT") |
| /* |
| Overloads: |
| 0. V - vector |
| 1. VTT - vector, r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t vec(parameters[0]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = vec.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| T result = T(0); |
| T error = T(0); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| details::kahan_sum(result,error,vec[i]); |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <typename T> |
| class axpy : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| axpy() |
| : exprtk::igeneric_function<T>("TVV|TVVTT") |
| /* |
| y <- ax + y |
| Overloads: |
| 0. TVV - a, x(vector), y(vector) |
| 1. TVVTT - a, x(vector), y(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[1]); |
| vector_t y(parameters[2]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| T a = scalar_t(parameters[0])(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| y[i] = a * x[i] + y[i]; |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class axpby : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| axpby() |
| : exprtk::igeneric_function<T>("TVTV|TVTVTT") |
| /* |
| y <- ax + by |
| Overloads: |
| 0. TVTV - a, x(vector), b, y(vector) |
| 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[1]); |
| vector_t y(parameters[3]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| const T a = scalar_t(parameters[0])(); |
| const T b = scalar_t(parameters[2])(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| y[i] = (a * x[i]) + (b * y[i]); |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class axpyz : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| axpyz() |
| : exprtk::igeneric_function<T>("TVVV|TVVVTT") |
| /* |
| z <- ax + y |
| Overloads: |
| 0. TVVV - a, x(vector), y(vector), z(vector) |
| 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[1]); |
| vector_t y(parameters[2]); |
| vector_t z(parameters[3]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(z,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| T a = scalar_t(parameters[0])(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| z[i] = a * x[i] + y[i]; |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class axpbyz : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| axpbyz() |
| : exprtk::igeneric_function<T>("TVTVV|TVTVVTT") |
| /* |
| z <- ax + by |
| Overloads: |
| 0. TVTVV - a, x(vector), b, y(vector), z(vector) |
| 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[1]); |
| vector_t y(parameters[3]); |
| vector_t z(parameters[4]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(z,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| const T a = scalar_t(parameters[0])(); |
| const T b = scalar_t(parameters[2])(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| z[i] = (a * x[i]) + (b * y[i]); |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class axpbz : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| axpbz() |
| : exprtk::igeneric_function<T>("TVTV|TVTVTT") |
| /* |
| z <- ax + b |
| Overloads: |
| 0. TVTV - a, x(vector), b, z(vector) |
| 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[1]); |
| vector_t z(parameters[3]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = x.size() - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(z,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| const T a = scalar_t(parameters[0])(); |
| const T b = scalar_t(parameters[2])(); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| z[i] = a * x[i] + b; |
| } |
| |
| return T(1); |
| } |
| }; |
| |
| template <typename T> |
| class dot : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| dot() |
| : exprtk::igeneric_function<T>("VV|VVTT") |
| /* |
| Overloads: |
| 0. VV - x(vector), y(vector) |
| 1. VVTT - x(vector), y(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[0]); |
| vector_t y(parameters[1]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| T result = T(0); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| result += (x[i] * y[i]); |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <typename T> |
| class dotk : public exprtk::igeneric_function<T> |
| { |
| public: |
| |
| typedef typename exprtk::igeneric_function<T> igfun_t; |
| typedef typename igfun_t::parameter_list_t parameter_list_t; |
| typedef typename igfun_t::generic_type generic_type; |
| typedef typename generic_type::scalar_view scalar_t; |
| typedef typename generic_type::vector_view vector_t; |
| |
| using exprtk::igeneric_function<T>::operator(); |
| |
| dotk() |
| : exprtk::igeneric_function<T>("VV|VVTT") |
| /* |
| Overloads: |
| 0. VV - x(vector), y(vector) |
| 1. VVTT - x(vector), y(vector), r0, r1 |
| */ |
| {} |
| |
| inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) |
| { |
| vector_t x(parameters[0]); |
| vector_t y(parameters[1]); |
| |
| std::size_t r0 = 0; |
| std::size_t r1 = std::min(x.size(),y.size()) - 1; |
| |
| if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| else if (helper::invalid_range(y,r0,r1)) |
| return std::numeric_limits<T>::quiet_NaN(); |
| |
| T result = T(0); |
| T error = T(0); |
| |
| for (std::size_t i = r0; i <= r1; ++i) |
| { |
| details::kahan_sum(result,error,(x[i] * y[i])); |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <typename T> |
| struct package |
| { |
| all_true <T> at; |
| all_false <T> af; |
| any_true <T> nt; |
| any_false <T> nf; |
| count <T> c; |
| copy <T> cp; |
| rol <T> rl; |
| ror <T> rr; |
| shift_left <T> sl; |
| shift_right<T> sr; |
| sort <T> st; |
| nthelement <T> ne; |
| iota <T> ia; |
| sumk <T> sk; |
| axpy <T> b1_axpy; |
| axpby <T> b1_axpby; |
| axpyz <T> b1_axpyz; |
| axpbyz <T> b1_axpbyz; |
| axpbz <T> b1_axpbz; |
| dot <T> dt; |
| dotk <T> dtk; |
| |
| bool register_package(exprtk::symbol_table<T>& symtab) |
| { |
| if (!symtab.add_function("all_true" ,at)) |
| return false; |
| else if (!symtab.add_function("all_false" ,af)) |
| return false; |
| else if (!symtab.add_function("any_true" ,nt)) |
| return false; |
| else if (!symtab.add_function("any_false" ,nf)) |
| return false; |
| else if (!symtab.add_function("count" , c)) |
| return false; |
| else if (!symtab.add_function("copy" , cp)) |
| return false; |
| else if (!symtab.add_function("rotate_left" ,rl)) |
| return false; |
| else if (!symtab.add_function("rol" ,rl)) |
| return false; |
| else if (!symtab.add_function("rotate_right" ,rr)) |
| return false; |
| else if (!symtab.add_function("ror" ,rr)) |
| return false; |
| else if (!symtab.add_function("shftl" ,sl)) |
| return false; |
| else if (!symtab.add_function("shftr" ,sr)) |
| return false; |
| else if (!symtab.add_function("sort" ,st)) |
| return false; |
| else if (!symtab.add_function("nth_element" ,ne)) |
| return false; |
| else if (!symtab.add_function("iota" ,ia)) |
| return false; |
| else if (!symtab.add_function("sumk" ,sk)) |
| return false; |
| else if (!symtab.add_function("axpy" ,b1_axpy)) |
| return false; |
| else if (!symtab.add_function("axpby" ,b1_axpby)) |
| return false; |
| else if (!symtab.add_function("axpyz" ,b1_axpyz)) |
| return false; |
| else if (!symtab.add_function("axpbyz",b1_axpbyz)) |
| return false; |
| else if (!symtab.add_function("axpbz" ,b1_axpbz)) |
| return false; |
| else if (!symtab.add_function("dot" ,dt)) |
| return false; |
| else if (!symtab.add_function("dotk" ,dtk)) |
| return false; |
| else |
| return true; |
| } |
| }; |
| |
| } // namespace exprtk::rtl::vecops |
| } // namespace exprtk::rtl |
| } // namespace exprtk |
| #endif |
| |
| namespace exprtk |
| { |
| namespace information |
| { |
| static const char* library = "Mathematical Expression Toolkit"; |
| static const char* version = "2.71828182845904523536028747135266249775" |
| "7247093699959574966967627724076630353547"; |
| static const char* date = "20161010"; |
| |
| static inline std::string data() |
| { |
| static const std::string info_str = std::string(library) + |
| std::string(" v") + std::string(version) + |
| std::string(" (") + date + std::string(")"); |
| return info_str; |
| } |
| |
| } // namespace information |
| |
| } // namespace exprtk |
| |
| #endif |