You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							30167 lines
						
					
					
						
							1.1 MiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							30167 lines
						
					
					
						
							1.1 MiB
						
					
					
				| /* | |
|  ****************************************************************** | |
|  *           C++ Mathematical Expression Toolkit Library          * | |
|  *                                                                * | |
|  * Author: Arash Partow (1999-2015)                               * | |
|  * 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 <cstdio> | |
| #include <cstdlib> | |
| #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 | |
| { | |
|    #if exprtk_enable_debugging | |
|      #define exprtk_debug(params) printf params | |
|    #else | |
|      #define exprtk_debug(params) (void)0 | |
|    #endif | |
| 
 | |
|    namespace details | |
|    { | |
|       inline bool is_whitespace(const char c) | |
|       { | |
|          return (' '  == c) || ('\n' == c) || | |
|                 ('\r' == c) || ('\t' == c) || | |
|                 ('\b' == c) || ('\v' == c) || | |
|                 ('\f' == c) ; | |
|       } | |
| 
 | |
|       inline bool is_operator_char(const char 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 c) | |
|       { | |
|          return (('a' <= c) && (c <= 'z')) || | |
|                 (('A' <= c) && (c <= 'Z')) ; | |
|       } | |
| 
 | |
|       inline bool is_digit(const char c) | |
|       { | |
|          return ('0' <= c) && (c <= '9'); | |
|       } | |
| 
 | |
|       inline bool is_letter_or_digit(const char c) | |
|       { | |
|          return is_letter(c) || is_digit(c); | |
|       } | |
| 
 | |
|       inline bool is_left_bracket(const char c) | |
|       { | |
|          return ('(' == c) || ('[' == c) || ('{' == c); | |
|       } | |
| 
 | |
|       inline bool is_right_bracket(const char c) | |
|       { | |
|          return (')' == c) || (']' == c) || ('}' == c); | |
|       } | |
| 
 | |
|       inline bool is_bracket(const char c) | |
|       { | |
|          return is_left_bracket(c) || is_right_bracket(c); | |
|       } | |
| 
 | |
|       inline bool is_sign(const char c) | |
|       { | |
|          return ('+' == c) || ('-' == c); | |
|       } | |
| 
 | |
|       inline bool is_invalid(const char 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 c1, const char 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 std::string to_str(int i) | |
|       { | |
|          if (0 == i) | |
|             return std::string("0"); | |
| 
 | |
|          std::string result; | |
|          bool negative = (i < 0); | |
| 
 | |
|          if (negative) i *= -1; | |
| 
 | |
|          while (i) | |
|          { | |
|             char digit = '0' + char(i % 10); | |
|             result = (digit + result); | |
|             i /= 10; | |
|          } | |
| 
 | |
|          if (negative) | |
|             result = "-" + result; | |
| 
 | |
|          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 unsigned char hex_to_bin(unsigned char h) | |
|       { | |
|          if (('0' <= h) && (h <= '9')) | |
|             return (h - '0'); | |
|          else | |
|             return (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) | |
|       { | |
|          std::string::iterator itr1 = s.begin(); | |
|          std::string::iterator itr2 = s.begin(); | |
|          std::string::iterator 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 c1 = static_cast<char>(std::tolower(s1[i])); | |
|                const char 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",  "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", "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); | |
| 
 | |
|       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; | |
|       } | |
| 
 | |
|       struct cs_match | |
|       { | |
|          static inline bool cmp(const char c0, const char c1) | |
|          { | |
|             return (c0 == c1); | |
|          } | |
|       }; | |
| 
 | |
|       struct cis_match | |
|       { | |
|          static inline bool cmp(const char c0, const char 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() || pattern.empty()) | |
|             return false; | |
|          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 target = std::toupper(*(p_itr - 1)); | |
| 
 | |
|                if ('*' == target) | |
|                { | |
|                   diff_index = std::distance(str.begin(),s_itr); | |
|                   diff_value = 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 = 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.718281828459045235360; | |
|             static const double pi      =  3.141592653589793238462; | |
|             static const double pi_2    =  1.570796326794896619231; | |
|             static const double pi_4    =  0.785398163397448309616; | |
|             static const double pi_180  =  0.017453292519943295769; | |
|             static const double _1_pi   =  0.318309886183790671538; | |
|             static const double _2_pi   =  0.636619772367581343076; | |
|             static const double _180_pi = 57.295779513082320876798; | |
|             static const double log2    =  0.693147180559945309417; | |
|             static const double sqrt2   =  1.414213562373095048801; | |
|          } | |
| 
 | |
|          namespace details | |
|          { | |
|             struct unknown_type_tag {}; | |
|             struct real_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_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_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) | |
|             { | |
|                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 nequal_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 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); | |
|             } | |
| 
 | |
|             template <typename T> | |
|             inline T erf_impl(T v, real_type_tag) | |
|             { | |
|                #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) | |
|                // Credits: Abramowitz & Stegun Equations 7.1.25-28 | |
|                const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); | |
|                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) | |
|                                     }; | |
|                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(v); | |
|                #endif | |
|             } | |
| 
 | |
|             template <typename T> | |
|             inline T erf_impl(T v, int_type_tag) | |
|             { | |
|                return erf_impl(static_cast<double>(v),real_type_tag()); | |
|             } | |
| 
 | |
|             template <typename T> | |
|             inline T erfc_impl(T v, real_type_tag) | |
|             { | |
|                #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) | |
|                return T(1) - erf_impl(v,real_type_tag()); | |
|                #else | |
|                return ::erfc(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) - 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 inf_uc[] = "INFINITY"; | |
|          static const char inf_lc[] = "infinity"; | |
|          static const std::size_t inf_length = 8; | |
|          const std::size_t length = std::distance(itr,end); | |
|          if ((3 != length) && (inf_length != length)) | |
|             return false; | |
|          const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; | |
|          while (end != itr) | |
|          { | |
|             if (*inf_itr == static_cast<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,-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 (*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; | |
| 
 | |
|          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); | |
|             } | |
|          } | |
| 
 | |
|       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 c0, const char 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 c0, const char 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 c0 = s_itr_[0]; | |
| 
 | |
|             if (!is_end(s_itr_ + 1)) | |
|             { | |
|                const char c1 = s_itr_[1]; | |
| 
 | |
|                if (!is_end(s_itr_ + 2)) | |
|                { | |
|                   const char 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_)) && | |
|                     (details::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_')) | |
|                   ) | |
|             { | |
|                ++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: | |
|                1. 123456 | |
|                2. 123.456 | |
|                3. 123.456e3 | |
|                4. 123.456E3 | |
|                5. 123.456e+3 | |
|                6. 123.456E+3 | |
|                7. 123.456e-3 | |
|                8. 123.456E-3 | |
|             */ | |
|             const char* initial_itr = s_itr_; | |
|             bool dot_found         = false; | |
|             bool e_found           = false; | |
|             bool post_e_sign_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_)) | |
|                { | |
|                   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 (('.' != (*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 ('\\' == *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_))) | |
|                   { | |
|                      if ( | |
|                           is_end(s_itr_ + 1) || | |
|                           is_end(s_itr_ + 2) || | |
|                           is_end(s_itr_ + 3) || | |
|                           ( | |
|                             ('x' != *(s_itr_ + 1)) && | |
|                             ('X' != *(s_itr_ + 1)) | |
|                           ) || | |
|                           (!details::is_hex_digit(*(s_itr_ + 2))) || | |
|                           (!details::is_hex_digit(*(s_itr_ + 3))) | |
|                         ) | |
|                      { | |
|                         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; | |
|          } | |
| 
 | |
|          inline virtual int insert(const token&, token& ) | |
|          { | |
|             return -1; | |
|          } | |
| 
 | |
|          inline virtual int insert(const token&, const token&, token&) | |
|          { | |
|             return -1; | |
|          } | |
| 
 | |
|          inline virtual int insert(const token&, const token&, const token&, token&) | |
|          { | |
|             return -1; | |
|          } | |
| 
 | |
|          inline virtual int insert(const token&, const token&, const token&, const token&, token&) | |
|          { | |
|             return -1; | |
|          } | |
| 
 | |
|          inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) | |
|          { | |
|             return -1; | |
|          } | |
| 
 | |
|       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.token_list_[i],g.token_list_[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.token_list_[i],g.token_list_[i + 1],g.token_list_[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: | |
| 
 | |
|             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 | |
|                   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: | |
| 
 | |
|             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]) | |
|                   ) | |
|                { | |
|                   char 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: | |
| 
 | |
|             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: | |
| 
 | |
|             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_colon  ); | |
|                add_invalid(lexer::token::e_string ,lexer::token::e_ternary); | |
|                add_invalid(lexer::token::e_colon  ,lexer::token::e_string ); | |
|                add_invalid(lexer::token::e_ternary,lexer::token::e_string ); | |
|                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); | |
|                bool result = true; | |
| 
 | |
|                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 result; | |
|             } | |
| 
 | |
|             inline bool run_joiners(lexer::generator& g) | |
|             { | |
|                error_token_joiner = reinterpret_cast<lexer::token_joiner*>(0); | |
|                bool result = true; | |
| 
 | |
|                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 result; | |
|             } | |
| 
 | |
|             inline bool run_inserters(lexer::generator& g) | |
|             { | |
|                error_token_inserter = reinterpret_cast<lexer::token_inserter*>(0); | |
|                bool result = true; | |
| 
 | |
|                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 result; | |
|             } | |
| 
 | |
|             inline bool run_scanners(lexer::generator& g) | |
|             { | |
|                error_token_scanner = reinterpret_cast<lexer::token_scanner*>(0); | |
|                bool result = true; | |
| 
 | |
|                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 result; | |
|             } | |
| 
 | |
|             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; | |
|          }; | |
|       } | |
|    } | |
| 
 | |
|    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_[size() - 1]; | |
|          } | |
| 
 | |
|          inline const type_store& back() const | |
|          { | |
|             return parameter_list_[size() - 1]; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          std::vector<type_store>& parameter_list_; | |
|       }; | |
| 
 | |
|       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 data_ + ts_.size; } | |
|          inline       value_t* end()         { return 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)) | |
|          {} | |
| 
 | |
|          value_t& operator()() | |
|          { | |
|             return v_; | |
|          } | |
| 
 | |
|          const value_t& operator()() const | |
|          { | |
|             return v_; | |
|          } | |
| 
 | |
|          T& v_; | |
|       }; | |
|    }; | |
| 
 | |
|    template <typename StringView> | |
|    inline std::string to_str(const StringView& view) | |
|    { | |
|       return std::string(view.begin(),view.size()); | |
|    } | |
| 
 | |
|    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 | |
|       }; | |
| 
 | |
|       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 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_quinary      , e_senary       , e_vararg       , e_conditional  , | |
|             e_while        , e_repeat       , e_for          , e_switch       , | |
|             e_mswitch      , 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_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_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 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() | |
|                 ); | |
|       } | |
| 
 | |
|       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_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> 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(); | |
|             } | |
| 
 | |
|          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_; | |
|          }; | |
| 
 | |
|       public: | |
| 
 | |
|          vector_holder(Type* vec, const std::size_t& vec_size) | |
|          : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) | |
|          {} | |
| 
 | |
|          template <typename Allocator> | |
|          vector_holder(std::vector<Type,Allocator>& vec) | |
|          : vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::vector>(vec)) | |
|          {} | |
| 
 | |
|          template <typename Allocator> | |
|          vector_holder(std::deque<Type,Allocator>& deq) | |
|          : vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::deque>(deq)) | |
|          {} | |
| 
 | |
|          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(); | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          mutable vector_holder_base* vector_holder_base_; | |
|          unsigned char 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_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 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_min     : return std::min<T>(std::min<T>(arg0,arg1),arg2); | |
|                case e_max     : return std::max<T>(std::max<T>(arg0,arg1),arg2); | |
|                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        : 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 | |
|          { | |
|             const T arg0 = branch_[0].first->value(); | |
|             const T arg1 = branch_[1].first->value(); | |
|             const T arg2 = branch_[2].first->value(); | |
|             const T arg3 = branch_[3].first->value(); | |
| 
 | |
|             switch (operation_) | |
|             { | |
|                case e_min : return std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3)); | |
|                case e_max : return std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3)); | |
|                default    : 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 quinary_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>* expression_ptr; | |
|          typedef std::pair<expression_ptr,bool> branch_t; | |
| 
 | |
|          quinary_node(const operator_type& opr, | |
|                       expression_ptr branch0, | |
|                       expression_ptr branch1, | |
|                       expression_ptr branch2, | |
|                       expression_ptr branch3, | |
|                       expression_ptr branch4) | |
|          : operation_(opr) | |
|          { | |
|             init_branches<5>(branch_,branch0,branch1,branch2,branch3,branch4); | |
|          } | |
| 
 | |
|         ~quinary_node() | |
|          { | |
|             cleanup_branches::execute<T,5>(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(); | |
|             const T arg3 = branch_[3].first->value(); | |
|             const T arg4 = branch_[4].first->value(); | |
| 
 | |
|             switch (operation_) | |
|             { | |
|                case e_min  : return std::min<T>(std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3)),arg4); | |
|                case e_max  : return std::max<T>(std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3)),arg4); | |
|                default     : return std::numeric_limits<T>::quiet_NaN(); | |
|             } | |
|          } | |
| 
 | |
|          inline typename expression_node<T>::node_type type() const | |
|          { | |
|             return expression_node<T>::e_quinary; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          operator_type operation_; | |
|          branch_t branch_[5]; | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class senary_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>* expression_ptr; | |
|          typedef std::pair<expression_ptr,bool> branch_t; | |
| 
 | |
|          senary_node(const operator_type& opr, | |
|                      expression_ptr branch0, | |
|                      expression_ptr branch1, | |
|                      expression_ptr branch2, | |
|                      expression_ptr branch3, | |
|                      expression_ptr branch4, | |
|                      expression_ptr branch5) | |
|          : operation_(opr) | |
|          { | |
|             init_branches<6>(branch_,branch0,branch1,branch2,branch3,branch4,branch5); | |
|          } | |
| 
 | |
|         ~senary_node() | |
|          { | |
|             cleanup_branches::execute<T,6>(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(); | |
|             const T arg3 = branch_[3].first->value(); | |
|             const T arg4 = branch_[4].first->value(); | |
|             const T arg5 = branch_[5].first->value(); | |
| 
 | |
|             switch (operation_) | |
|             { | |
|                case e_min     : return std::min<T>(std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3)),std::min<T>(arg4,arg5)); | |
|                case e_max     : return std::max<T>(std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3)),std::max<T>(arg4,arg5)); | |
|                case e_default : | |
|                default        : return std::numeric_limits<T>::quiet_NaN(); | |
|             } | |
|          } | |
| 
 | |
|          inline typename expression_node<T>::node_type type() const | |
|          { | |
|             return expression_node<T>::e_senary; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          operator_type operation_; | |
|          branch_t branch_[6]; | |
|       }; | |
| 
 | |
|       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 std::exception | |
|       { | |
|       public: | |
| 
 | |
|          break_exception(const T& v) | |
|          : value(v) | |
|          {} | |
| 
 | |
|          T value; | |
|       }; | |
| 
 | |
|       class continue_exception : public std::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; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          std::vector<expression_ptr> arg_list_; | |
|          std::vector<unsigned char> delete_branch_; | |
|       }; | |
| 
 | |
|       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 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; | |
| 
 | |
|          virtual ~vector_interface() | |
|          {} | |
| 
 | |
|          virtual vector_node_ptr vec() const = 0; | |
| 
 | |
|          virtual vector_node_ptr vec() = 0; | |
| 
 | |
|          virtual std::size_t size() const = 0; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|          vector_node(vector_holder_t* vh) | |
|          : vector_holder_(vh) | |
|          {} | |
| 
 | |
|          inline T value() const | |
|          { | |
|             return *(ref()[0]); | |
|          } | |
| 
 | |
|          inline const vector_holder_t& ref() const | |
|          { | |
|             return (*vector_holder_); | |
|          } | |
| 
 | |
|          inline vector_holder_t& ref() | |
|          { | |
|             return (*vector_holder_); | |
|          } | |
| 
 | |
|          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 ref().size(); | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_holder_t* vector_holder_; | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class vector_elem_node : public expression_node<T>, | |
|                                public ivariable<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>* expression_ptr; | |
| 
 | |
|          vector_elem_node(expression_ptr index, T* vector_base) | |
|          : index_(index), | |
|            vector_base_(vector_base), | |
|            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; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          expression_ptr index_; | |
|          T* vector_base_; | |
|          bool index_deletable_; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|          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) | |
|          { | |
|             if (is_ivector_node(binary_node<T>::branch_[0].first)) | |
|             { | |
|                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); | |
| 
 | |
|                if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) | |
|                { | |
|                   vec0_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (is_ivector_node(binary_node<T>::branch_[1].first)) | |
|             { | |
|                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); | |
| 
 | |
|                if ((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_->ref().size(), | |
|                                     vec1_node_ptr_->ref().size()); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                binary_node<T>::branch_[0].first->value(); | |
|                binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
| 
 | |
|                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_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec0_node_ptr_; | |
|          vector_node<T>* vec1_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       #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_).data(); | |
|          } | |
| 
 | |
|          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, range_t rp) | |
|          : value_(&v), | |
|            rp_(rp) | |
|          {} | |
| 
 | |
|         ~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_).data(); | |
|          } | |
| 
 | |
|          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, 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; | |
|          typedef typename range_t::cached_range_t cached_range_t; | |
| 
 | |
|          generic_string_range_node(expression_ptr str_branch, 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_.data(); | |
|          } | |
| 
 | |
|          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 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; | |
|          typedef typename range_t::cached_range_t cached_range_t; | |
| 
 | |
|          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_.data(); | |
|          } | |
| 
 | |
|          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; | |
|          typedef typename range_t::cached_range_t cached_range_t; | |
| 
 | |
|          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 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; | |
|          typedef typename range_t::cached_range_t cached_range_t; | |
| 
 | |
|          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; | |
|          typedef typename range_t::cached_range_t cached_range_t; | |
| 
 | |
|          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_; | |
|       }; | |
|       #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)") | |
| 
 | |
|       #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_vec_node : public binary_node<T>, | |
|                                   public vector_interface<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>* expression_ptr; | |
|          typedef vector_node<T>*    vector_node_ptr; | |
| 
 | |
|          assignment_vec_node(const operator_type& opr, | |
|                              expression_ptr branch0, | |
|                              expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec_node_ptr_(0), | |
|            vec_size_    (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); | |
|                vec_size_     = vec_node_ptr_->ref().size(); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec_hldr = vec_node_ptr_->ref(); | |
|                const T v = binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   (*vec_hldr[i]) = v; | |
|                } | |
| 
 | |
|                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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|          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), | |
|            vec_size_     (0) | |
|          { | |
|             if (is_vector_node(binary_node<T>::branch_[0].first)) | |
|             { | |
|                vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); | |
|             } | |
| 
 | |
|             if (is_vector_node(binary_node<T>::branch_[1].first)) | |
|             { | |
|                vec1_node_ptr_ = static_cast<vector_node<T>*>(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 ((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_->ref().size(), | |
|                                     vec1_node_ptr_->ref().size()); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   (*vec0[i]) = (*vec1[i]); | |
|                } | |
| 
 | |
|                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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec0_node_ptr_; | |
|          vector_node<T>* vec1_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       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_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; | |
| 
 | |
|          assignment_vec_op_node(const operator_type& opr, | |
|                                 expression_ptr branch0, | |
|                                 expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec_node_ptr_(0), | |
|            vec_size_    (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); | |
|                vec_size_     = vec_node_ptr_->ref().size(); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec_hldr = vec_node_ptr_->ref(); | |
|                const T v = binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   T& vec_i = *vec_hldr[i]; | |
|                      vec_i = Operation::process(vec_i,v); | |
|                } | |
| 
 | |
|                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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|          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), | |
|            vec_size_     (0) | |
|          { | |
|             if (is_vector_node(binary_node<T>::branch_[0].first)) | |
|             { | |
|                vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); | |
|             } | |
| 
 | |
|             if (is_vector_node(binary_node<T>::branch_[1].first)) | |
|             { | |
|                vec1_node_ptr_ = static_cast<vector_node<T>*>(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 ((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_->ref().size(), | |
|                                     vec1_node_ptr_->ref().size()); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                binary_node<T>::branch_[0].first->value(); | |
|                binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   T& vec0_i = *vec0[i]; | |
|                   T& vec1_i = *vec1[i]; | |
|                   vec0_i = Operation::process(vec0_i,vec1_i); | |
|                } | |
| 
 | |
|                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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec0_node_ptr_; | |
|          vector_node<T>* vec1_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class eqineq_vecvec_node : public binary_node<T>, | |
|                                  public vector_interface<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>*  expression_ptr; | |
|          typedef vector_node<T>*     vector_node_ptr; | |
| 
 | |
|          eqineq_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), | |
|            vec_size_     (0) | |
|          { | |
| 
 | |
|             if (is_vector_node(binary_node<T>::branch_[0].first)) | |
|             { | |
|                vec0_node_ptr_ = static_cast<vector_node<T>*>(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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) | |
|                { | |
|                   vec0_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (is_vector_node(binary_node<T>::branch_[1].first)) | |
|             { | |
|                vec1_node_ptr_ = static_cast<vector_node<T>*>(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 ((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_->ref().size(), | |
|                                     vec1_node_ptr_->ref().size()); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                binary_node<T>::branch_[0].first->value(); | |
|                binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   if (std::equal_to<T>()(T(0),Operation::process(*vec0[i],*vec1[i]))) | |
|                   { | |
|                      return T(0); | |
|                   } | |
|                } | |
| 
 | |
|                return T(1); | |
|             } | |
|             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_vecvecineq; | |
|          } | |
| 
 | |
|          std::size_t size() const | |
|          { | |
|             return vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec0_node_ptr_; | |
|          vector_node<T>* vec1_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class eqineq_vecval_node : public binary_node<T>, | |
|                                  public vector_interface<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>*  expression_ptr; | |
|          typedef vector_node<T>*     vector_node_ptr; | |
| 
 | |
|          eqineq_vecval_node(const operator_type& opr, | |
|                             expression_ptr branch0, | |
|                             expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec_node_ptr_(0), | |
|            vec_size_    (0) | |
|          { | |
|             if (is_vector_node(binary_node<T>::branch_[0].first)) | |
|             { | |
|                vec_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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) | |
|                { | |
|                   vec_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec_node_ptr_) | |
|             { | |
|                vec_size_ = vec_node_ptr_->ref().size(); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec_node_ptr_) | |
|             { | |
|                      binary_node<T>::branch_[0].first->value(); | |
|                T v = binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec_hldr = vec_node_ptr_->ref(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   if (std::equal_to<T>()(T(0),Operation::process(*vec_hldr[i],v))) | |
|                   { | |
|                      return T(0); | |
|                   } | |
|                } | |
| 
 | |
|                return T(1); | |
|             } | |
|             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_vecvalineq; | |
|          } | |
| 
 | |
|          std::size_t size() const | |
|          { | |
|             return vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class eqineq_valvec_node : public binary_node<T>, | |
|                                  public vector_interface<T> | |
|       { | |
|       public: | |
| 
 | |
|          typedef expression_node<T>*  expression_ptr; | |
|          typedef vector_node<T>*     vector_node_ptr; | |
| 
 | |
|          eqineq_valvec_node(const operator_type& opr, | |
|                             expression_ptr branch0, | |
|                             expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec_node_ptr_(0), | |
|            vec_size_    (0) | |
|          { | |
|             if (is_vector_node(binary_node<T>::branch_[1].first)) | |
|             { | |
|                vec_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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) | |
|                { | |
|                   vec_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec_node_ptr_) | |
|             { | |
|                vec_size_ = vec_node_ptr_->ref().size(); | |
|             } | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec_node_ptr_) | |
|             { | |
|                T v = binary_node<T>::branch_[0].first->value(); | |
|                      binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec_hldr = vec_node_ptr_->ref(); | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   if (std::equal_to<T>()(T(0),Operation::process(v,*vec_hldr[i]))) | |
|                   { | |
|                      return T(0); | |
|                   } | |
|                } | |
| 
 | |
|                return T(1); | |
|             } | |
|             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_valvecineq; | |
|          } | |
| 
 | |
|          std::size_t size() const | |
|          { | |
|             return vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node<T>* vec_node_ptr_; | |
|          std::size_t     vec_size_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class vecarith_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; | |
| 
 | |
|          vecarith_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), | |
|            vec_size_     (0), | |
|            data_         (0), | |
|            temp_         (0), | |
|            temp_vec_node_(0) | |
|          { | |
|             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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) | |
|                { | |
|                   vec0_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) | |
|                { | |
|                   vec1_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
| 
 | |
|                vec_size_      = std::min(vec0.size(),vec1.size()); | |
|                data_          = new T[vec_size_]; | |
|                temp_          = new vector_holder<T>(data_,vec_size_); | |
|                temp_vec_node_ = new vector_node<T>  (temp_); | |
|             } | |
|          } | |
| 
 | |
|         ~vecarith_vecvec_node() | |
|          { | |
|             delete[] data_; | |
|             delete   temp_; | |
|             delete   temp_vec_node_; | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             if (vec0_node_ptr_ && vec1_node_ptr_) | |
|             { | |
|                binary_node<T>::branch_[0].first->value(); | |
|                binary_node<T>::branch_[1].first->value(); | |
| 
 | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
|                vector_holder<T>& vec2 = *temp_; | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
| 
 | |
|                   T& vec0_i = *vec0[i]; | |
|                   T& vec1_i = *vec1[i]; | |
|                   T& vec2_i = *vec2[i]; | |
| 
 | |
|                   vec2_i = Operation::process(vec0_i,vec1_i); | |
|                } | |
| 
 | |
|                return *vec2[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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node_ptr   vec0_node_ptr_; | |
|          vector_node_ptr   vec1_node_ptr_; | |
|          std::size_t       vec_size_; | |
|          T*                data_; | |
|          vector_holder_ptr temp_; | |
|          vector_node_ptr   temp_vec_node_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class vecarith_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; | |
| 
 | |
|          vecarith_vecval_node(const operator_type& opr, | |
|                               expression_ptr branch0, | |
|                               expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec0_node_ptr_(0), | |
|            vec_size_     (0), | |
|            data_         (0), | |
|            temp_         (0), | |
|            temp_vec_node_(0) | |
|          { | |
|             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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) | |
|                { | |
|                   vec0_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec0_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
| 
 | |
|                vec_size_      = vec0.size(); | |
|                data_          = new T[vec_size_]; | |
|                temp_          = new vector_holder<T>(data_,vec_size_); | |
|                temp_vec_node_ = new vector_node<T>  (temp_); | |
|             } | |
|          } | |
| 
 | |
|         ~vecarith_vecval_node() | |
|          { | |
|             delete[] data_; | |
|             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(); | |
| 
 | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = *temp_; | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   T& vec0_i = *vec0[i]; | |
|                   T& vec1_i = *vec1[i]; | |
| 
 | |
|                   vec1_i = Operation::process(vec0_i,v); | |
|                } | |
| 
 | |
|                return *vec1[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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node_ptr   vec0_node_ptr_; | |
|          std::size_t       vec_size_; | |
|          T*                data_; | |
|          vector_holder_ptr temp_; | |
|          vector_node_ptr   temp_vec_node_; | |
|       }; | |
| 
 | |
|       template <typename T, typename Operation> | |
|       class vecarith_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; | |
| 
 | |
|          vecarith_valvec_node(const operator_type& opr, | |
|                               expression_ptr branch0, | |
|                               expression_ptr branch1) | |
|          : binary_node<T>(opr,branch0,branch1), | |
|            vec1_node_ptr_(0), | |
|            vec_size_     (0), | |
|            data_         (0), | |
|            temp_         (0), | |
|            temp_vec_node_(0) | |
|          { | |
|             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 ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) | |
|                { | |
|                   vec1_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec1_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec1_node_ptr_->ref(); | |
| 
 | |
|                vec_size_      = vec0.size(); | |
|                data_          = new T[vec_size_]; | |
|                temp_          = new vector_holder<T>(data_,vec_size_); | |
|                temp_vec_node_ = new vector_node<T>  (temp_); | |
|             } | |
|          } | |
| 
 | |
|         ~vecarith_valvec_node() | |
|          { | |
|             delete[] data_; | |
|             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(); | |
| 
 | |
|                vector_holder<T>& vec1 = vec1_node_ptr_->ref(); | |
|                vector_holder<T>& vec2 = *temp_; | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   T& vec1_i = *vec1[i]; | |
|                   T& vec2_i = *vec2[i]; | |
| 
 | |
|                   vec2_i = Operation::process(v,vec1_i); | |
|                } | |
| 
 | |
|                return *vec2[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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node_ptr   vec1_node_ptr_; | |
|          std::size_t       vec_size_; | |
|          T*                data_; | |
|          vector_holder_ptr temp_; | |
|          vector_node_ptr   temp_vec_node_; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|          unary_vector_node(const operator_type& opr, expression_ptr branch0) | |
|          : unary_node<T>(opr,branch0), | |
|            vec0_node_ptr_(0), | |
|            vec_size_     (0), | |
|            data_         (0), | |
|            temp_         (0), | |
|            temp_vec_node_(0) | |
|          { | |
|             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 ((vi = dynamic_cast<vector_interface<T>*>(unary_node<T>::branch_))) | |
|                { | |
|                   vec0_node_ptr_ = vi->vec(); | |
|                } | |
|             } | |
| 
 | |
|             if (vec0_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
| 
 | |
|                vec_size_      = vec0.size(); | |
|                data_          = new T[vec_size_]; | |
|                temp_          = new vector_holder<T>(data_,vec_size_); | |
|                temp_vec_node_ = new vector_node<T>  (temp_); | |
|             } | |
|          } | |
| 
 | |
|         ~unary_vector_node() | |
|          { | |
|             delete[] data_; | |
|             delete   temp_; | |
|             delete   temp_vec_node_; | |
|          } | |
| 
 | |
|          inline T value() const | |
|          { | |
|             unary_node<T>::branch_->value(); | |
| 
 | |
|             if (vec0_node_ptr_) | |
|             { | |
|                vector_holder<T>& vec0 = vec0_node_ptr_->ref(); | |
|                vector_holder<T>& vec1 = *temp_; | |
| 
 | |
|                for (std::size_t i = 0; i < vec_size_; ++i) | |
|                { | |
|                   T& vec0_i = *vec0[i]; | |
|                   T& vec1_i = *vec1[i]; | |
| 
 | |
|                   vec1_i = Operation::process(vec0_i); | |
|                } | |
| 
 | |
|                return *vec1[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 vec_size_; | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          vector_node_ptr   vec0_node_ptr_; | |
|          std::size_t       vec_size_; | |
|          T*                data_; | |
|          vector_holder_ptr temp_; | |
|          vector_node_ptr   temp_vec_node_; | |
|       }; | |
| 
 | |
|       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_elem_node<T>          vector_elem_node_t; | |
|          typedef vector_node<T>                    vector_node_t; | |
|          typedef variable_node_t*            variable_node_ptr_t; | |
|          typedef vector_elem_node_t*      vector_elem_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(GenericFunction* func, | |
|                                const std::vector<expression_ptr>& arg_list) | |
|          : function_(func), | |
|            arg_list_(arg_list) | |
|          {} | |
| 
 | |
|         ~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->vec()->ref()[0]; | |
|                   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; | |
| 
 | |
|                   if (is_generally_string_node(arg_list_[i])) | |
|                   { | |
|                      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 if (is_vector_elem_node(arg_list_[i])) | |
|                { | |
|                   vector_elem_node_ptr_t var = vector_elem_node_ptr_t(0); | |
| 
 | |
|                   if (0 == (var = dynamic_cast<vector_elem_node_ptr_t>(arg_list_[i]))) | |
|                      return false; | |
| 
 | |
|                   ts.size = 1; | |
|                   ts.data = reinterpret_cast<void*>(&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(func,arg_list) | |
|          { | |
|             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_.data(); | |
|          } | |
| 
 | |
|          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(func,arg_list), | |
|            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_; | |
|       }; | |
| 
 | |
|       #define exprtk_define_unary_op(OpName)                         \ | |
|       template <typename T>                                          \ | |
|       struct OpName##_op                                             \ | |
|       {                                                              \ | |
|          typedef typename functor_t<T>::Type Type;                   \ | |
|                                                                      \ | |
|          static inline T process(Type v)                             \ | |
|          {                                                           \ | |
|             return numeric:: OpName (v);                             \ | |
|          }                                                           \ | |
|                                                                      \ | |
|          static inline typename expression_node<T>::node_type 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> 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; | |
|          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 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; | |
|          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 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; | |
|          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 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; | |
|          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 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; | |
|          static inline T process(Type t1, Type t2) { return 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; | |
|          static inline T process(Type t1, Type t2) { return 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 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) | |
|          { | |
|             vector_holder<T>& vec = v->vec()->ref(); | |
| 
 | |
|             T result = T(0); | |
| 
 | |
|             for (std::size_t i = 0; i < vec.size(); ++i) | |
|             { | |
|               result += (*vec[i]); | |
|             } | |
| 
 | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       struct vec_mul_op | |
|       { | |
|          typedef vector_interface<T>* ivector_ptr; | |
| 
 | |
|          static inline T process(const ivector_ptr v) | |
|          { | |
|             vector_holder<T>& vec = v->vec()->ref(); | |
| 
 | |
|             T result = (*vec[0]); | |
| 
 | |
|             for (std::size_t i = 1; i < vec.size(); ++i) | |
|             { | |
|               result *= (*vec[i]); | |
|             } | |
| 
 | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       struct vec_avg_op | |
|       { | |
|          typedef vector_interface<T>* ivector_ptr; | |
| 
 | |
|          static inline T process(const ivector_ptr v) | |
|          { | |
|             vector_holder<T>& vec = v->vec()->ref(); | |
| 
 | |
|             T result = T(0); | |
| 
 | |
|             for (std::size_t i = 0; i < vec.size(); ++i) | |
|             { | |
|               result += (*vec[i]); | |
|             } | |
| 
 | |
|             return result / vec.size(); | |
|          } | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       struct vec_min_op | |
|       { | |
|          typedef vector_interface<T>* ivector_ptr; | |
| 
 | |
|          static inline T process(const ivector_ptr v) | |
|          { | |
|             vector_holder<T>& vec = v->vec()->ref(); | |
| 
 | |
|             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) | |
|          { | |
|             vector_holder<T>& vec = v->vec()->ref(); | |
| 
 | |
|             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: | |
| 
 | |
|          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: | |
| 
 | |
|          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: | |
| 
 | |
|          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 const T& v() const = 0; | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class bov_base_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          virtual const T& v() const = 0; | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class cob_base_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          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: | |
| 
 | |
|          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: | |
| 
 | |
|          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: | |
| 
 | |
|          inline virtual operator_type operation() const | |
|          { | |
|             return details::e_default; | |
|          } | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class sosos_base_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          inline virtual operator_type operation() const | |
|          { | |
|             return details::e_default; | |
|          } | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class T0oT1oT2_base_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          virtual std::string type_id() const = 0; | |
|       }; | |
| 
 | |
|       template <typename T> | |
|       class T0oT1oT2oT3_base_node : public expression_node<T> | |
|       { | |
|       public: | |
| 
 | |
|          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 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 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> | |
|       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_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   : 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 | |
| 
 | |
|    template <typename T> | |
|    class ifunction | |
|    { | |
|    public: | |
| 
 | |
|       explicit ifunction(const std::size_t& pc, const bool hse = true) | |
|       : param_count(pc), | |
|         has_side_effects(hse) | |
|       {} | |
| 
 | |
|       virtual ~ifunction() | |
|       {} | |
| 
 | |
|       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(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, | |
|                                   const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) | |
|       { | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       std::size_t param_count; | |
|       bool has_side_effects; | |
|    }; | |
| 
 | |
|    template <typename T> | |
|    class ivararg_function | |
|    { | |
|    public: | |
| 
 | |
|       ivararg_function(const bool hse = true) | |
|       : has_side_effects(hse) | |
|       {} | |
| 
 | |
|       virtual ~ivararg_function() | |
|       {} | |
| 
 | |
|       inline virtual T operator()(const std::vector<T>&) | |
|       { | |
|          exprtk_debug(("ivararg_function::operator() - Operator has not been overriden.\n")); | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       bool has_side_effects; | |
|    }; | |
| 
 | |
|    template <typename T> | |
|    class igeneric_function | |
|    { | |
|    public: | |
| 
 | |
|       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 bool hse = true) | |
|       : has_side_effects(hse), | |
|         parameter_sequence(param_seq) | |
|       {} | |
| 
 | |
|       virtual ~igeneric_function() | |
|       {} | |
| 
 | |
|       // f(i_0,i_1,....,i_N) --> Number | |
|       inline virtual T operator()(parameter_list_t) | |
|       { | |
|          exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [1]\n")); | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       // f(i_0,i_1,....,i_N) --> String | |
|       inline virtual T operator()(std::string&, parameter_list_t) | |
|       { | |
|          exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [2]\n")); | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       // f(psi,i_0,i_1,....,i_N) --> Number | |
|       inline virtual T operator()(const std::size_t&, parameter_list_t) | |
|       { | |
|          exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [3]\n")); | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       // f(psi,i_0,i_1,....,i_N) --> String | |
|       inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) | |
|       { | |
|          exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [4]\n")); | |
|          return std::numeric_limits<T>::quiet_NaN(); | |
|       } | |
| 
 | |
|       bool has_side_effects; | |
|       std::string parameter_sequence; | |
|    }; | |
| 
 | |
|    template <typename T> class parser; | |
|    template <typename T> class expression_helper; | |
| 
 | |
|    template <typename T> | |
|    class symbol_table | |
|    { | |
|    protected: | |
| 
 | |
|       template <typename Type> class parser; | |
| 
 | |
|    protected: | |
| 
 | |
|       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_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); | |
|          } | |
| 
 | |
|          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); | |
|                } | |
|             }; | |
| 
 | |
|             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; | |
|          } | |
| 
 | |
|          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 st_holder | |
|       { | |
|          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]); | |
|                } | |
|             } | |
| 
 | |
|             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_; | |
|          }; | |
| 
 | |
|          st_holder() | |
|          : ref_count(1), | |
|            data_(new st_data) | |
|          {} | |
| 
 | |
|          st_holder(st_data* data) | |
|          : ref_count(1), | |
|            data_(data) | |
|          {} | |
| 
 | |
|         ~st_holder() | |
|          { | |
|             if (data_ && (0 == ref_count)) | |
|             { | |
|                delete data_; | |
|                data_ = 0; | |
|             } | |
|          } | |
| 
 | |
|          std::size_t ref_count; | |
|          st_data* data_; | |
|       }; | |
| 
 | |
|    public: | |
| 
 | |
|       symbol_table() | |
|       : holder_(new st_holder) | |
|       { | |
|          clear(); | |
|       } | |
| 
 | |
|      ~symbol_table() | |
|       { | |
|          if (holder_) | |
|          { | |
|             if (0 == --holder_->ref_count) | |
|             { | |
|                clear(); | |
|                delete holder_; | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       symbol_table(const symbol_table<T>& st) | |
|       { | |
|          holder_ = st.holder_; | |
|          holder_->ref_count++; | |
|       } | |
| 
 | |
|       inline symbol_table<T>& operator=(const symbol_table<T>& st) | |
|       { | |
|          if (holder_) | |
|          { | |
|             if (0 == --holder_->ref_count) | |
|             { | |
|                delete holder_; | |
|             } | |
| 
 | |
|             holder_ = 0; | |
|          } | |
| 
 | |
|          holder_ = st.holder_; | |
|          holder_->ref_count++; | |
| 
 | |
|          return *this; | |
|       } | |
| 
 | |
|       inline bool operator==(const symbol_table<T>& st) | |
|       { | |
|          return (this == &st) || (holder_ == st.holder_); | |
|       } | |
| 
 | |
|       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); | |
|       } | |
| 
 | |
|       enum func_type | |
|       { | |
|          e_ft_unknown   = 0, | |
|          e_ft_basicfunc = 1, | |
|          e_ft_strfunc   = 2 | |
|       }; | |
| 
 | |
|       inline bool add_function(const std::string& function_name, generic_function_t& function, const func_type ft = e_ft_basicfunc) | |
|       { | |
|          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("STV*?|")) | |
|             return false; | |
|          else if (e_ft_basicfunc == ft) | |
|             return local_data().generic_function_store.add(function_name,function); | |
|          else if (e_ft_strfunc == ft) | |
|             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); | |
|       } | |
| 
 | |
|       template <typename Allocator> | |
|       inline bool add_vector(const std::string& vector_name, std::deque<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 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 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 | |
|       { | |
|          /* | |
|             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 (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 holder_ && holder_->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,e_ft_strfunc); | |
|                } | |
|             } | |
|          } | |
|       } | |
| 
 | |
|    private: | |
| 
 | |
|       inline bool valid_symbol(const std::string& symbol) const | |
|       { | |
|          if (symbol.empty()) | |
|             return false; | |
|          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(symbol[i])) && | |
|                     (!details:: is_digit(symbol[i])) && | |
|                     ('_' != symbol[i]) | |
|                   ) | |
|                { | |
|                   return false; | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          return (!local_data().is_reserved_symbol(symbol)); | |
|       } | |
| 
 | |
|       inline typename st_holder::st_data& local_data() | |
|       { | |
|          return *(holder_->data_); | |
|       } | |
| 
 | |
|       inline const typename st_holder::st_data& local_data() const | |
|       { | |
|          return *(holder_->data_); | |
|       } | |
| 
 | |
|       st_holder* holder_; | |
|    }; | |
| 
 | |
|    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; | |
| 
 | |
|       struct expression_holder | |
|       { | |
|          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; | |
| 
 | |
|          expression_holder() | |
|          : ref_count(0), | |
|            expr(0) | |
|          {} | |
| 
 | |
|          expression_holder(expression_ptr e) | |
|          : ref_count(1), | |
|            expr(e) | |
|          {} | |
| 
 | |
|         ~expression_holder() | |
|          { | |
|             if (expr && details::branch_deletable(expr)) | |
|             { | |
|                delete expr; | |
|             } | |
| 
 | |
|             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; | |
|                   } | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          std::size_t ref_count; | |
|          expression_ptr expr; | |
|          local_data_list_t local_data_list; | |
| 
 | |
|          friend class function_compositor<T>; | |
|       }; | |
| 
 | |
|    public: | |
| 
 | |
|       expression() | |
|       : expression_holder_(0) | |
|       { | |
|          set_expression(new details::null_node<T>()); | |
|       } | |
| 
 | |
|       expression(const expression<T>& e) | |
|       : expression_holder_(e.expression_holder_), | |
|         symbol_table_(e.symbol_table_) | |
|       { | |
|          expression_holder_->ref_count++; | |
|       } | |
| 
 | |
|       inline expression<T>& operator=(const expression<T>& e) | |
|       { | |
|          if (this != &e) | |
|          { | |
|             if (expression_holder_) | |
|             { | |
|                if (0 == --expression_holder_->ref_count) | |
|                { | |
|                   delete expression_holder_; | |
|                } | |
| 
 | |
|                expression_holder_ = 0; | |
|             } | |
| 
 | |
|             expression_holder_ = e.expression_holder_; | |
|             expression_holder_->ref_count++; | |
|             symbol_table_ = e.symbol_table_; | |
|          } | |
| 
 | |
|          return *this; | |
|       } | |
| 
 | |
|       inline bool operator==(const expression<T>& e) | |
|       { | |
|          return (this == &e); | |
|       } | |
| 
 | |
|       inline bool operator!() const | |
|       { | |
|          return ( | |
|                   (0 == expression_holder_      ) || | |
|                   (0 == expression_holder_->expr) | |
|                 ); | |
|       } | |
| 
 | |
|       inline expression<T>& release() | |
|       { | |
|          if (expression_holder_) | |
|          { | |
|             if (0 == --expression_holder_->ref_count) | |
|             { | |
|                delete expression_holder_; | |
|             } | |
| 
 | |
|             expression_holder_ = 0; | |
|          } | |
| 
 | |
|          return *this; | |
|       } | |
| 
 | |
|      ~expression() | |
|       { | |
|          if (expression_holder_) | |
|          { | |
|             if (0 == --expression_holder_->ref_count) | |
|             { | |
|                delete expression_holder_; | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       inline T value() const | |
|       { | |
|          return expression_holder_->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_ = st; | |
|       } | |
| 
 | |
|       inline const symbol_table<T>& get_symbol_table() const | |
|       { | |
|          return symbol_table_; | |
|       } | |
| 
 | |
|       inline symbol_table<T>& get_symbol_table() | |
|       { | |
|          return symbol_table_; | |
|       } | |
| 
 | |
|    private: | |
| 
 | |
|       inline void set_expression(const expression_ptr expr) | |
|       { | |
|          if (expr) | |
|          { | |
|             if (expression_holder_) | |
|             { | |
|                if (0 == --expression_holder_->ref_count) | |
|                { | |
|                   delete expression_holder_; | |
|                } | |
|             } | |
| 
 | |
|             expression_holder_ = new expression_holder(expr); | |
|          } | |
|       } | |
| 
 | |
|       inline void register_local_var(expression_ptr expr) | |
|       { | |
|          if (expr) | |
|          { | |
|             if (expression_holder_) | |
|             { | |
|                expression_holder_-> | |
|                   local_data_list.push_back( | |
|                      typename expression<T>::expression_holder:: | |
|                         data_pack(reinterpret_cast<void*>(expr), | |
|                                   expression_holder::e_expr)); | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       inline void register_local_var(vector_holder_ptr vec_holder) | |
|       { | |
|          if (vec_holder) | |
|          { | |
|             if (expression_holder_) | |
|             { | |
|                expression_holder_-> | |
|                   local_data_list.push_back( | |
|                      typename expression<T>::expression_holder:: | |
|                         data_pack(reinterpret_cast<void*>(vec_holder), | |
|                                   expression_holder::e_vecholder)); | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       inline void register_local_data(void* data, const std::size_t& size = 0, const bool vectype = false) | |
|       { | |
|          if (data) | |
|          { | |
|             if (expression_holder_) | |
|             { | |
|                expression_holder_-> | |
|                   local_data_list.push_back( | |
|                      typename expression<T>::expression_holder:: | |
|                         data_pack(reinterpret_cast<void*>(data), | |
|                                   vectype ? expression_holder::e_vecdata : | |
|                                             expression_holder::e_data, | |
|                                   size)); | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       inline const typename expression_holder::local_data_list_t& local_data_list() | |
|       { | |
|          if (expression_holder_) | |
|          { | |
|             return expression_holder_->local_data_list; | |
|          } | |
|          else | |
|          { | |
|             static typename expression_holder::local_data_list_t null_local_data_list; | |
|             return null_local_data_list; | |
|          } | |
|       } | |
| 
 | |
|       expression_holder* expression_holder_; | |
|       symbol_table<T> symbol_table_; | |
| 
 | |
|       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.expression_holder_->expr); | |
|       } | |
| 
 | |
|       static inline bool is_variable(const expression<T>& expr) | |
|       { | |
|          return details::is_variable_node(expr.expression_holder_->expr); | |
|       } | |
| 
 | |
|       static inline bool is_unary(const expression<T>& expr) | |
|       { | |
|          return details::is_unary_node(expr.expression_holder_->expr); | |
|       } | |
| 
 | |
|       static inline bool is_binary(const expression<T>& expr) | |
|       { | |
|          return details::is_binary_node(expr.expression_holder_->expr); | |
|       } | |
| 
 | |
|       static inline bool is_function(const expression<T>& expr) | |
|       { | |
|          return details::is_function(expr.expression_holder_->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(((diagnostic + "\n").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(((diagnostic + "\n").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 char 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 | |
|    { | |
|    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::quinary_node    <T>                   quinary_node_t; | |
|       typedef details::senary_node     <T>                    senary_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::vector_node     <T>                    vector_node_t; | |
|       #ifndef exprtk_disable_string_capabilities | |
|       typedef details::range_pack         <T>                       range_t; | |
|       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; | |
|       #endif | |
|       typedef details::assignment_node<T>                 assignment_node_t; | |
|       typedef details::assignment_vec_elem_node<T> assignment_vec_elem_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 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 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; | |
| 
 | |
|       struct scope_element | |
|       { | |
|          enum element_type | |
|          { | |
|             e_none    , | |
|             e_variable, | |
|             e_vector  , | |
|             e_vecelem , | |
|             e_string | |
|          }; | |
| 
 | |
|          typedef variable_node_t* variable_node_ptr; | |
|          typedef details::vector_holder<T> vector_holder_t; | |
|          typedef vector_holder_t* vector_holder_ptr; | |
| 
 | |
|          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) | |
|          {} | |
| 
 | |
|          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); | |
|          } | |
| 
 | |
|          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; | |
|          variable_node_ptr var_node; | |
|          vector_holder_ptr vec_node; | |
|       }; | |
| 
 | |
|       class scope_element_manager | |
|       { | |
|       public: | |
| 
 | |
|          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()) | |
|          { | |
|             for (std::size_t i = 0; i < element_.size(); ++i) | |
|             { | |
|                scope_element& se = element_[i]; | |
| 
 | |
|                if (se.depth > parser_.scope_depth_) | |
|                   return null_element_; | |
|                else if ( | |
|                          (se.name  == var_name) && | |
|                          (se.index == index) | |
|                        ) | |
|                   return se; | |
|             } | |
| 
 | |
|             return null_element_; | |
|          } | |
| 
 | |
|          inline bool add_element(const scope_element& se) | |
|          { | |
|             for (std::size_t j = 0; j < element_.size(); ++j) | |
|             { | |
|                if ( | |
|                     (element_[j].name  == se.name ) && | |
|                     (element_[j].depth <= se.depth) && | |
|                     (element_[j].index == se.index) && | |
|                     (element_[j].size  == se.size ) | |
|                   ) | |
|                   return false; | |
|             } | |
| 
 | |
|             element_.push_back(se); | |
|             std::sort(element_.begin(),element_.end()); | |
| 
 | |
|             return true; | |
|          } | |
| 
 | |
|          inline void deactivate(const std::size_t& scope_depth) | |
|          { | |
|             for (std::size_t j = 0; j < element_.size(); ++j) | |
|             { | |
|                if (element_[j].depth >= scope_depth) | |
|                { | |
|                   element_[j].active = false; | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          void cleanup() | |
|          { | |
|             for (std::size_t i = 0; i < element_.size(); ++i) | |
|             { | |
|                if (element_[i].var_node) | |
|                { | |
|                   delete element_[i].var_node; | |
|                } | |
| 
 | |
|                if (element_[i].vec_node) | |
|                { | |
|                   delete element_[i].vec_node; | |
|                } | |
| 
 | |
|                T* data = (T*)(element_[i].data); | |
| 
 | |
|                switch (element_[i].type) | |
|                { | |
|                   case scope_element::e_variable : delete    data; break; | |
|                   case scope_element::e_vector   : delete [] data; break; | |
|                   default                        : break; | |
|                } | |
|             } | |
| 
 | |
|             element_.clear(); | |
| 
 | |
|             input_param_cnt_ = 0; | |
|          } | |
| 
 | |
|          inline std::size_t next_ip_index() | |
|          { | |
|             return ++input_param_cnt_; | |
|          } | |
| 
 | |
|          inline variable_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) | |
|                { | |
|                   if (&se.var_node->ref() == (&v)) | |
|                   { | |
|                      return se.var_node; | |
|                   } | |
|                } | |
|             } | |
| 
 | |
|             return variable_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_.scope_depth_++; | |
|             #ifdef exprtk_enable_debugging | |
|             std::string depth(2 * parser_.scope_depth_,'-'); | |
|             exprtk_debug(("%s> Scope Depth: %02d\n",depth.c_str(),static_cast<int>(parser_.scope_depth_))); | |
|             #endif | |
|          } | |
| 
 | |
|         ~scope_handler() | |
|          { | |
|             parser_.scope_depth_--; | |
|             parser_.sem_.deactivate(parser_.scope_depth_); | |
|             #ifdef exprtk_enable_debugging | |
|             std::string depth(2 * parser_.scope_depth_,'-'); | |
|             exprtk_debug(("<%s Scope Depth: %02d\n",depth.c_str(),static_cast<int>(parser_.scope_depth_))); | |
|             #endif | |
|          } | |
| 
 | |
|       private: | |
| 
 | |
|          scope_handler& operator=(const scope_handler&); | |
| 
 | |
|          parser_t& parser_; | |
|       }; | |
| 
 | |
|    public: | |
| 
 | |
|       enum 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 | |
|       }; | |
| 
 | |
|       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 = ""; | |
| 
 | |
|             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_string         = 3, | |
|          e_st_function       = 4, | |
|          e_st_local_variable = 5, | |
|          e_st_local_vector   = 6, | |
|          e_st_local_string   = 7 | |
|       }; | |
| 
 | |
|       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) | |
|          {} | |
| 
 | |
|          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(); | |
|          } | |
| 
 | |
|          bool& collect_variables() | |
|          { | |
|             return collect_variables_; | |
|          } | |
| 
 | |
|          bool& collect_functions() | |
|          { | |
|             return collect_functions_; | |
|          } | |
| 
 | |
|          bool& collect_assignments() | |
|          { | |
|             return collect_assignments_; | |
|          } | |
| 
 | |
|       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_; | |
|          symbol_list_t symbol_name_list_; | |
|          symbol_list_t assignment_name_list_; | |
| 
 | |
|          friend class parser<T>; | |
|       }; | |
| 
 | |
|       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; | |
| 
 | |
|       parser(const std::size_t compile_options = compile_all_opts) | |
|       : compile_options_(compile_options), | |
|         resolve_unknown_symbol_(false), | |
|         vardef_disabled_((compile_options & e_disable_vardef) == e_disable_vardef), | |
|         scope_depth_(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(strength_reduction_enabled()); | |
|       } | |
| 
 | |
|      ~parser() | |
|       {} | |
| 
 | |
|       inline void init_precompilation() | |
|       { | |
|          if (collect_variables_enabled()) | |
|             dec_.collect_variables() = true; | |
| 
 | |
|          if (collect_functions_enabled()) | |
|             dec_.collect_functions() = true; | |
| 
 | |
|          if (collect_assignments_enabled()) | |
|             dec_.collect_assignments() = true; | |
| 
 | |
|          if (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 (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 (joiner_enabled()) | |
|          { | |
|             helper_assembly_.token_joiner_list.clear(); | |
|             helper_assembly_.register_joiner(&operator_joiner_2_); | |
|             helper_assembly_.register_joiner(&operator_joiner_3_); | |
|          } | |
| 
 | |
|          if ( | |
|               numeric_check_enabled () || | |
|               bracket_check_enabled () || | |
|               sequence_check_enabled() | |
|             ) | |
|          { | |
|             helper_assembly_.token_scanner_list.clear(); | |
| 
 | |
|             if (numeric_check_enabled()) | |
|             { | |
|                helper_assembly_.register_scanner(&numeric_checker_); | |
|             } | |
| 
 | |
|             if (bracket_check_enabled()) | |
|             { | |
|                helper_assembly_.register_scanner(&bracket_checker_); | |
|             } | |
| 
 | |
|             if (sequence_check_enabled()) | |
|             { | |
|                helper_assembly_.register_scanner(&sequence_validator_); | |
|             } | |
|          } | |
|       } | |
| 
 | |
|       inline bool compile(const std::string& expression_string, expression<T>& expr) | |
|       { | |
|          error_list_     .clear(); | |
|          brkcnt_list_    .clear(); | |
|          synthesis_error_.clear(); | |
|          sem_            .cleanup(); | |
| 
 | |
|          expression_generator_.set_allocator(node_allocator_); | |
| 
 | |
|          scope_depth_ = 0; | |
| 
 | |
|          if (expression_string.empty()) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           "ERR00 - Empty expression!")); | |
| 
 | |
|             return false; | |
|          } | |
| 
 | |
|          if (!lexer_.process(expression_string)) | |
|          { | |
|             process_lexer_errors(); | |
|             return false; | |
|          } | |
| 
 | |
|          if (lexer_.empty()) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           "ERR01 - Empty expression!")); | |
| 
 | |
|             return false; | |
|          } | |
| 
 | |
|          if (!run_assemblies()) | |
|          { | |
|             return false; | |
|          } | |
| 
 | |
|          symbol_table_ = expr.get_symbol_table(); | |
|          dec_.clear(); | |
| 
 | |
|          lexer_.begin(); | |
|          next_token(); | |
| 
 | |
|          expression_node_ptr e = parse_corpus(); | |
| 
 | |
|          if ((0 != e) && (token_t::e_eof == current_token_.type)) | |
|          { | |
|             expr.set_expression(e); | |
|             register_local_vars(expr); | |
| 
 | |
|             return !(!expr); | |
|          } | |
|          else | |
|          { | |
|             if (error_list_.empty()) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR02 - Invalid expression encountered")); | |
|             } | |
| 
 | |
|             dec_.clear  (); | |
|             sem_.cleanup(); | |
| 
 | |
|             if (0 != 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 = "ERR03 - "; | |
| 
 | |
|                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 replacer_enabled() const | |
|       { | |
|          return ((compile_options_ & e_replacer) == e_replacer); | |
|       } | |
| 
 | |
|       inline bool commutative_check_enabled() const | |
|       { | |
|          return ((compile_options_ & e_commutative_check) == e_commutative_check); | |
|       } | |
| 
 | |
|       inline bool joiner_enabled() const | |
|       { | |
|          return ((compile_options_ & e_joiner) == e_joiner); | |
|       } | |
| 
 | |
|       inline bool numeric_check_enabled() const | |
|       { | |
|          return ((compile_options_ & e_numeric_check) == e_numeric_check); | |
|       } | |
| 
 | |
|       inline bool bracket_check_enabled() const | |
|       { | |
|          return ((compile_options_ & e_bracket_check) == e_bracket_check); | |
|       } | |
| 
 | |
|       inline bool sequence_check_enabled() const | |
|       { | |
|          return ((compile_options_ & e_sequence_check) == e_sequence_check); | |
|       } | |
| 
 | |
|       inline bool strength_reduction_enabled() const | |
|       { | |
|          return ((compile_options_ & e_strength_reduction) == e_strength_reduction); | |
|       } | |
| 
 | |
|       inline bool collect_variables_enabled() const | |
|       { | |
|          return ((compile_options_ & e_collect_vars) == e_collect_vars); | |
|       } | |
| 
 | |
|       inline bool collect_functions_enabled() const | |
|       { | |
|          return ((compile_options_ & e_collect_funcs) == e_collect_funcs); | |
|       } | |
| 
 | |
|       inline bool collect_assignments_enabled() const | |
|       { | |
|          return ((compile_options_ & e_collect_assings) == e_collect_assings); | |
|       } | |
| 
 | |
|       inline bool run_assemblies() | |
|       { | |
|          if (commutative_check_enabled()) | |
|          { | |
|             helper_assembly_.run_inserters(lexer_); | |
|          } | |
| 
 | |
|          if (joiner_enabled()) | |
|          { | |
|             helper_assembly_.run_joiners(lexer_); | |
|          } | |
| 
 | |
|          if (replacer_enabled()) | |
|          { | |
|             helper_assembly_.run_modifiers(lexer_); | |
|          } | |
| 
 | |
|          if ( | |
|               numeric_check_enabled () || | |
|               bracket_check_enabled () || | |
|               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(), | |
|                                    "ERR04 - 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, | |
|                                       "ERR05 - 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, | |
|                                       "ERR06 - 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 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 (!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 (!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 (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) | |
|                ); | |
|       } | |
| 
 | |
|       inline void store_token() | |
|       { | |
|          lexer_.store(); | |
|          store_current_token_ = current_token_; | |
|       } | |
| 
 | |
|       inline void restore_token() | |
|       { | |
|          lexer_.restore(); | |
|          current_token_ = store_current_token_; | |
|       } | |
| 
 | |
|       #ifndef exprtk_enable_debugging | |
|       inline void next_token() | |
|       { | |
|          current_token_ = lexer_.next_token(); | |
|       } | |
|       #else | |
|       inline void next_token() | |
|       { | |
|          std::string ct_str = current_token_.value; | |
|          current_token_ = lexer_.next_token(); | |
|          std::string depth(2 * scope_depth_,' '); | |
|          exprtk_debug(("%s" | |
|                        "prev[%s] --> curr[%s]\n", | |
|                        depth.c_str(), | |
|                        ct_str.c_str(), | |
|                        current_token_.value.c_str())); | |
|       } | |
|       #endif | |
| 
 | |
|       inline const lexer::token& current_token() const | |
|       { | |
|          return current_token_; | |
|       } | |
| 
 | |
|       inline expression_node_ptr parse_corpus() | |
|       { | |
|          std::vector<expression_node_ptr> arg_list; | |
|          expression_node_ptr result = error_node(); | |
| 
 | |
|          scoped_vec_delete<expression_node_t> sdd(*this,arg_list); | |
| 
 | |
|          for (;;) | |
|          { | |
|             expression_node_ptr arg = parse_expression(); | |
| 
 | |
|             if (0 == arg) | |
|             { | |
|                if (error_list_.empty()) | |
|                { | |
|                   set_error( | |
|                      make_error(parser_error::e_syntax, | |
|                                 current_token_, | |
|                                 "ERR07 - Invalid expression encountered")); | |
|                } | |
| 
 | |
|                return error_node(); | |
|             } | |
|             else | |
|                arg_list.push_back(arg); | |
| 
 | |
|             if (lexer_.finished()) | |
|                break; | |
|             else if (token_is(token_t::e_eof,false)) | |
|             { | |
|                if (lexer_.finished()) | |
|                   break; | |
|                else | |
|                   next_token(); | |
|             } | |
|          } | |
| 
 | |
|          result = simplify(arg_list); | |
| 
 | |
|          sdd.delete_ptr = (0 == result); | |
|          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; | |
|          } | |
| 
 | |
|          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_level01,e_level02,details::e_and); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_and1)) | |
|                                            { | |
|                                               #ifndef exprtk_disable_sc_andor | |
|                                               current_state.set(e_level01,e_level02,details::e_scand); | |
|                                               #else | |
|                                               current_state.set(e_level01,e_level02,details::e_and); | |
|                                               #endif | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_nand)) | |
|                                            { | |
|                                               current_state.set(e_level01,e_level02,details::e_nand); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_or)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_or); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_or1)) | |
|                                            { | |
|                                               #ifndef exprtk_disable_sc_andor | |
|                                               current_state.set(e_level03,e_level04,details::e_scor); | |
|                                               #else | |
|                                               current_state.set(e_level03,e_level04,details::e_or); | |
|                                               #endif | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_nor)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_nor); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_xor)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_xor); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_xnor)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_xnor); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_in)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_in); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_like)) | |
|                                            { | |
|                                               current_state.set(e_level03,e_level04,details::e_like); | |
|                                               break; | |
|                                            } | |
|                                            else if (details::imatch(current_token_.value,s_ilike)) | |
|                                            { | |
|                                               current_state.set(e_level03,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 ((right_branch = parse_expression(current_state.right))) | |
|             { | |
|                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_ : | |
|                                 "ERR08 - General parsing error at token: '" + prev_token.value + "'")); | |
|                } | |
| 
 | |
|                free_node(node_allocator_,expression); | |
| 
 | |
|                return error_node(); | |
|             } | |
|             else | |
|             { | |
|                expression = new_expression; | |
| 
 | |
|                if (token_is(token_t::e_ternary,false) && (precedence == e_level00)) | |
|                { | |
|                   expression = parse_ternary_conditional_statement(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> > ubn_t; | |
| 
 | |
|             ubn_t* n = dynamic_cast<ubn_t*>(node); | |
| 
 | |
|             if (n) | |
|             { | |
|                const T& v = n->v(); | |
|                expression_node_ptr return_node = error_node(); | |
| 
 | |
|                if ( | |
|                     (return_node = symbol_table_.get_variable(v)) || | |
|                     (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_, | |
|                                 "ERR09 - 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>&); | |
|       }; | |
| 
 | |
|       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_, | |
|                                        "ERR10 - 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_, | |
|                           "ERR11 - 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) | |
|       { | |
|          if (0 == NumberofParameters) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR12 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          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_, | |
|                           "ERR13 - 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_, | |
|                              "ERR14 - 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_, | |
|                                 "ERR15 - 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_, | |
|                           "ERR16 - 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); | |
|          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_, | |
|                           "ERR17 - 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_, | |
|                           "ERR18 - 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_, | |
|                              "ERR19 - 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_, | |
|                           "ERR20 - No entry found for base operation: " + operation_name)); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          const std::size_t MaxNumberofParameters = 6; | |
|          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 <= 6) | |
|          { | |
|             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) | |
|                      base_opr_case(5) | |
|                      base_opr_case(6) | |
|                      #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_, | |
|                        "ERR21 - 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_, | |
|                           "ERR22 - 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_, | |
|                           "ERR23 - 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_, | |
|                           "ERR24 - 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_, | |
|                           "ERR25 - 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_, | |
|                           "ERR26 - Expected ')' at the end of if-statement")); | |
|             result = false; | |
|          } | |
| 
 | |
|          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,false)) | |
|          { | |
|             if (0 == (consequent = parse_multi_sequence("if-statement-01"))) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR27 - Failed to parse body of consequent for if-statement")); | |
|                result = false; | |
|             } | |
|          } | |
|          else | |
|          { | |
|             if ( | |
|                  commutative_check_enabled() && | |
|                  token_is(token_t::e_mul,false) | |
|                ) | |
|             { | |
|                next_token(); | |
|             } | |
| 
 | |
|             if (0 != (consequent = parse_expression())) | |
|             { | |
|                if (!token_is(token_t::e_eof)) | |
|                { | |
|                   set_error( | |
|                      make_error(parser_error::e_syntax, | |
|                                 current_token_, | |
|                                 "ERR28 - Expected ';' at the end of the consequent for if-statement")); | |
|                   result = false; | |
|                } | |
|             } | |
|             else | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR29 - 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,false)) | |
|                { | |
|                   if (0 == (alternative = parse_multi_sequence("else-statement-01"))) | |
|                   { | |
|                      set_error( | |
|                         make_error(parser_error::e_syntax, | |
|                                    current_token_, | |
|                                    "ERR30 - 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_, | |
|                                    "ERR31 - 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_, | |
|                                    "ERR32 - 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_, | |
|                                 "ERR33 - Failed to parse body of the 'else' for if-statement")); | |
|                   result = false; | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          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_, | |
|                           "ERR34 - 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_, | |
|                           "ERR35 - Failed to parse condition for if-statement")); | |
| 
 | |
|             return error_node(); | |
|          } | |
|          else if (token_is(token_t::e_comma,false)) | |
|          { | |
|             // 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_, | |
|                        "ERR36 - 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_, | |
|                           "ERR37 - 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_, | |
|                           "ERR38 - 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_, | |
|                           "ERR39 - Failed to parse consequent for if-statement")); | |
| 
 | |
|             result = false; | |
|          } | |
|          else if (!token_is(token_t::e_colon)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR40 - 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_, | |
|                           "ERR41 - Failed to parse alternative for if-statement")); | |
| 
 | |
|             result = false; | |
|          } | |
| 
 | |
|          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_, | |
|                           "ERR42 - 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_, | |
|                           "ERR43 - 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_, | |
|                           "ERR44 - 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_, | |
|                              "ERR45 - 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_, | |
|                              "ERR46 - 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; | |
|          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); | |
| 
 | |
|             for (;;) | |
|             { | |
|                expression_node_ptr arg = parse_expression(); | |
| 
 | |
|                if (0 == arg) | |
|                   return error_node(); | |
|                else | |
|                   arg_list.push_back(arg); | |
| 
 | |
|                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_, | |
|                                 "ERR47 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
| 
 | |
|                if (details::imatch(current_token_.value,"until")) | |
|                { | |
|                   next_token(); | |
|                   break; | |
|                } | |
|             } | |
| 
 | |
|             branch = simplify(arg_list); | |
| 
 | |
|             if ((sdd.delete_ptr = (0 == branch))) | |
|             { | |
|                brkcnt_list_.pop_front(); | |
| 
 | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR48 - 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_, | |
|                           "ERR49 - 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_, | |
|                           "ERR50 - 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_, | |
|                           "ERR51 - 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_, | |
|                           "ERR52 - 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_, | |
|                           "ERR53 - Expected '(' at start of for-loop")); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          if (!token_is(token_t::e_eof)) | |
|          { | |
|             if ( | |
|                  !token_is(token_t::e_symbol,false) && | |
|                  details::imatch(current_token_.value,"var") | |
|                ) | |
|             { | |
|                next_token(); | |
| 
 | |
|                if (!token_is(token_t::e_symbol,false)) | |
|                { | |
|                   set_error( | |
|                      make_error(parser_error::e_syntax, | |
|                                 current_token_, | |
|                                 "ERR54 - 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_, | |
|                                 "ERR55 - 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_, | |
|                                 "ERR56 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|                else if (!symbol_table_.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.type     = scope_element::e_variable; | |
|                      nse.depth    = scope_depth_; | |
|                      nse.data     = new T(T(0)); | |
|                      nse.var_node = new variable_node_t(*(T*)(nse.data)); | |
| 
 | |
|                      if (!sem_.add_element(nse)) | |
|                      { | |
|                         set_error( | |
|                            make_error(parser_error::e_syntax, | |
|                                       current_token_, | |
|                                       "ERR57 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); | |
| 
 | |
|                         result = false; | |
| 
 | |
|                      } | |
|                      else | |
|                         exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); | |
|                   } | |
|                } | |
|             } | |
| 
 | |
|             if (0 == (initialiser = parse_expression())) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR58 - Failed to parse initialiser of for-loop")); | |
|                result = false; | |
|             } | |
| 
 | |
|             if (!token_is(token_t::e_eof)) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR59 - 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_, | |
|                              "ERR60 - 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_, | |
|                              "ERR61 - 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_, | |
|                              "ERR62 - 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_, | |
|                              "ERR63 - 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_, | |
|                              "ERR64 - 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_, | |
|                           "ERR65 - 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_, | |
|                           "ERR66 - 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_, | |
|                              "ERR67 - 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_, | |
|                              "ERR68 - 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_, | |
|                              "ERR69 - Expected ';' at end of case for switch statement")); | |
| 
 | |
|                return error_node(); | |
|             } | |
| 
 | |
|             // Can we optimize 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_, | |
|                                 "ERR70 - Expected ':' for default of switch statement")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
| 
 | |
|                expression_node_ptr default_statement = parse_expression(); | |
| 
 | |
|                if (0 == default_statement) | |
|                   return error_node(); | |
|                else if (!token_is(token_t::e_eof)) | |
|                { | |
|                   set_error( | |
|                      make_error(parser_error::e_syntax, | |
|                                 current_token_, | |
|                                 "ERR71 - 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_, | |
|                           "ERR72 - 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_, | |
|                           "ERR73 - 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_, | |
|                           "ERR74 - 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_, | |
|                              "ERR75 - 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_, | |
|                              "ERR76 - 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_, | |
|                              "ERR77 - Expected ';' at end of case for [*] statement")); | |
| 
 | |
|                return error_node(); | |
|             } | |
| 
 | |
|             // Can we optimize 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,false)) | |
|             { | |
|                break; | |
|             } | |
|          } | |
| 
 | |
|          if (!token_is(token_t::e_rcrlbracket)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR78 - 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_, | |
|                           "ERR79 - Unsupported vararg function: " + symbol)); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          scoped_vec_delete<expression_node_t> sdd(*this,arg_list); | |
| 
 | |
|          next_token(); | |
|          if (!token_is(token_t::e_lbracket)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR80 - 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_, | |
|                              "ERR81 - 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; | |
|       } | |
| 
 | |
|       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_, | |
|                           "ERR82 - 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_, | |
|                           "ERR83 - Failed to generate string range node")); | |
| 
 | |
|             free_node(node_allocator_,expression); | |
|          } | |
| 
 | |
|          rp.clear(); | |
| 
 | |
|          return result; | |
|       } | |
| 
 | |
|       inline void parse_pending_string_rangesize(expression_node_ptr& expression) | |
|       { | |
|          const std::size_t max_rangesize_parses = 100; | |
|          std::size_t i = 0; | |
| 
 | |
|          while | |
|             ( | |
|                (0 != expression)                      && | |
|                (i++ < max_rangesize_parses)           && | |
|                error_list_.empty()                    && | |
|                token_is(token_t::e_lsqrbracket,false) && | |
|                is_generally_string_node(expression) | |
|             ) | |
|          { | |
|             expression = parse_string_range_statement(expression); | |
|          } | |
|       } | |
| 
 | |
|       template <typename Allocator, | |
|                 template <typename,typename> class Sequence> | |
|       inline expression_node_ptr simplify(Sequence<expression_node_ptr,Allocator>& expression_list) | |
|       { | |
|          if (expression_list.empty()) | |
|             return error_node(); | |
|          else if (1 == expression_list.size()) | |
|             return expression_list[0]; | |
| 
 | |
|          Sequence<expression_node_ptr,Allocator> tmp_expression_list; | |
| 
 | |
|          for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) | |
|          { | |
|             if (is_variable_node(expression_list[i])) | |
|                continue; | |
|             else if ( | |
|                       is_constant_node(expression_list[i]) || | |
|                       is_null_node    (expression_list[i]) | |
|                     ) | |
|             { | |
|                free_node(node_allocator_,expression_list[i]); | |
|                continue; | |
|             } | |
|             else | |
|                tmp_expression_list.push_back(expression_list[i]); | |
|          } | |
| 
 | |
|          tmp_expression_list.push_back(expression_list.back()); | |
|          expression_list.swap(tmp_expression_list); | |
| 
 | |
|          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_, | |
|                              "ERR84 - 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; | |
|          expression_node_ptr result = error_node(); | |
| 
 | |
|          scoped_vec_delete<expression_node_t> sdd(*this,arg_list); | |
| 
 | |
|          scope_handler sh(*this); | |
| 
 | |
|          for (;;) | |
|          { | |
|             expression_node_ptr arg = parse_expression(); | |
| 
 | |
|             if (0 == arg) | |
|                return error_node(); | |
|             else | |
|                arg_list.push_back(arg); | |
| 
 | |
|             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_, | |
|                              "ERR85 - 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); | |
| 
 | |
|          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_, | |
|                           "ERR86 - 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_, | |
|                              "ERR87 - 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_, | |
|                                 "ERR88 - 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_, | |
|                              "ERR89 - 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_, | |
|                              "ERR90 - 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_, | |
|                                 "ERR91 - 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_, | |
|                              "ERR92 - 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_, | |
|                              "ERR93 - 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); | |
|       } | |
| 
 | |
|       inline expression_node_ptr parse_string() | |
|       { | |
|          const std::string symbol = current_token_.value; | |
| 
 | |
|          if (!symbol_table_.is_conststr_stringvar(symbol)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR94 - Unknown string symbol")); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          expression_node_ptr result = symbol_table_.get_stringvar(symbol); | |
| 
 | |
|          typedef details::stringvar_node<T>* strvar_node_t; | |
|          strvar_node_t const_str_node = static_cast<strvar_node_t>(0); | |
| 
 | |
|          const bool is_const_string = symbol_table_.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; | |
|       } | |
| 
 | |
|       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_, | |
|                              "ERR95 - Overflow in range for string: '" + const_str + "'[" + | |
|                              (rp.n0_c.first ? details::to_str(rp.n0_c.second) : "?") + ":" + | |
|                              (rp.n1_c.first ? details::to_str(rp.n1_c.second) : "?") + "]")); | |
| 
 | |
|                return error_node(); | |
|             } | |
| 
 | |
|             result = expression_generator_(const_str,rp); | |
| 
 | |
|             if (result) | |
|                rp.clear(); | |
|          } | |
|          else | |
|             next_token(); | |
| 
 | |
|          return result; | |
|       } | |
| 
 | |
|       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_element(symbol); | |
| 
 | |
|          if ( | |
|               (se.name != symbol)       || | |
|               (se.depth > scope_depth_) || | |
|               (scope_element::e_vector != se.type) | |
|             ) | |
|          { | |
|             if (0 == (vec = symbol_table_.get_vector(symbol))) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR96 - 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_, | |
|                           "ERR97 - 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_, | |
|                           "ERR98 - 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)) | |
|             { | |
|                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_, | |
|                                    "ERR99 - Expected ',' for call to vararg function: " + vararg_function_name)); | |
| 
 | |
|                      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) | |
|             { | |
|                std::size_t diff_index = 0; | |
|                char        diff_value = 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(), | |
|                                 "ERR100 - 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(), | |
|                                 "ERR101 - 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_; | |
|          } | |
| 
 | |
|       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 (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(), | |
|                                    "ERR102 - 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(), | |
|                                    "ERR103 - 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_, | |
|                           "ERR104 - Type checker instantiation failure for generic function: " + function_name)); | |
| 
 | |
|             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 assumed to be 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_, | |
|                                    "ERR105 - Expected ',' for call to generic 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_, | |
|                           "ERR106 - 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_, | |
|                                    "ERR107 - 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_, | |
|                           "ERR108 - 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(), | |
|                                "ERR109 - 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(), | |
|                                      "ERR110 - 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_, | |
|                           "ERR111 - 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_, | |
|                           "ERR112 - 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 (!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_, | |
|                                 "ERR113 - 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_, | |
|                                 "ERR114 - Expected ']' at the completion of break's return expression")); | |
| 
 | |
|                   free_node(node_allocator_,return_expr); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|             } | |
| 
 | |
|             return node_allocator_.allocate<details::break_node<T> >(return_expr); | |
|          } | |
|          else | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR115 - 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; | |
|             return node_allocator_.allocate<details::continue_node<T> >(); | |
|          } | |
|          else | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR116 - 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_, | |
|                           "ERR117 - 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_, | |
|                           "ERR118 - 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_, | |
|                           "ERR119 - 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_, | |
|                           "ERR120 - 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; | |
| 
 | |
|          if (!token_is(token_t::e_rsqrbracket)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR121 - 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_, | |
|                              "ERR122 - 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_, | |
|                                 "ERR123 - 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_, | |
|                                 "ERR124 - Expected ']' to close single value vector initialiser")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
| 
 | |
|                single_value_initialiser = true; | |
|             } | |
|             else if (!token_is(token_t::e_lcrlbracket)) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR125 - Expected '{' as part of vector initialiser list")); | |
| 
 | |
|                return error_node(); | |
|             } | |
|             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_, | |
|                                    "ERR126 - 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_, | |
|                                    "ERR127 - Expected ',' between vector initialisers")); | |
| 
 | |
|                      return error_node(); | |
|                   } | |
| 
 | |
|                   if (token_is(token_t::e_rcrlbracket)) | |
|                      break; | |
|                } | |
|             } | |
| 
 | |
|             if ( | |
|                  !token_is(token_t::e_rbracket   ,false) && | |
|                  !token_is(token_t::e_rcrlbracket,false) && | |
|                  !token_is(token_t::e_rsqrbracket,false) | |
|                ) | |
|             { | |
|                if (!token_is(token_t::e_eof)) | |
|                { | |
|                   set_error( | |
|                      make_error(parser_error::e_syntax, | |
|                                 current_token_, | |
|                                 "ERR128 - 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_, | |
|                              "ERR129 - 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_, | |
|                              "ERR130 - 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.ref_count++; | |
|             } | |
|          } | |
| 
 | |
|          if (0 == vec_holder) | |
|          { | |
|             scope_element nse; | |
|             nse.name     = vec_name; | |
|             nse.type     = scope_element::e_vector; | |
|             nse.depth    = 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_, | |
|                              "ERR131 - Failed to add new local vector '" + vec_name + "' to SEM")); | |
| 
 | |
|                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))); | |
|          } | |
| 
 | |
|          lodge_symbol(vec_name,e_st_local_vector); | |
| 
 | |
|          expression_node_ptr 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; | |
|       } | |
| 
 | |
|       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 (vardef_disabled_) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR132 - 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_, | |
|                           "ERR133 - 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_, | |
|                           "ERR134 - Illegal redefinition of reserved keyword: '" + var_name + "'")); | |
| 
 | |
|             return error_node(); | |
|          } | |
|          else if (symbol_table_.symbol_exists(var_name)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR135 - 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_, | |
|                           "ERR136 - Illegal redefinition of local variable: '" + var_name + "'")); | |
| 
 | |
|             return error_node(); | |
|          } | |
|          else if (token_is(token_t::e_lsqrbracket,false)) | |
|          { | |
|             return parse_define_vector_statement(var_name); | |
|          } | |
|          else if (token_is(token_t::e_lcrlbracket,false)) | |
|          { | |
|             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_, | |
|                              "ERR137 - Failed to parse initialisation expression")); | |
| 
 | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          if ( | |
|               !token_is(token_t::e_rbracket   ,false) && | |
|               !token_is(token_t::e_rcrlbracket,false) && | |
|               !token_is(token_t::e_rsqrbracket,false) | |
|             ) | |
|          { | |
|             if (!token_is(token_t::e_eof,false)) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR138 - Expected ';' after variable definition")); | |
| 
 | |
|                free_node(node_allocator_,initialisation_expression); | |
| 
 | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          variable_node_t* var_node = reinterpret_cast<variable_node_t*>(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_, | |
|                              "ERR139 - 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.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     = scope_depth_; | |
|             nse.data      = new T(T(0)); | |
|             nse.var_node  = new variable_node_t(*(T*)(nse.data)); | |
| 
 | |
|             if (!sem_.add_element(nse)) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR140 - Failed to add new local variable '" + var_name + "' to SEM")); | |
| 
 | |
|                free_node(node_allocator_,initialisation_expression); | |
| 
 | |
|                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())); | |
|          } | |
| 
 | |
|          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_, | |
|                           "ERR141 - Expected a '{}' for uninitialised var definition")); | |
| 
 | |
|             return error_node(); | |
|          } | |
|          else if (!token_is(token_t::e_eof,false)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR142 - Expected ';' after uninitialised variable definition")); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          variable_node_t* var_node = reinterpret_cast<variable_node_t*>(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_, | |
|                              "ERR143 - 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     = scope_depth_; | |
|             nse.ip_index  = sem_.next_ip_index(); | |
|             nse.data      = new T(T(0)); | |
|             nse.var_node  = new variable_node_t(*(T*)(nse.data)); | |
| 
 | |
|             if (!sem_.add_element(nse)) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR144 - Failed to add new local variable '" + var_name + "' to SEM")); | |
| 
 | |
|                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); | |
| 
 | |
|          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_, | |
|                           "ERR145 - 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,false)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR146 - 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_, | |
|                              "ERR147 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); | |
| 
 | |
|                return error_node(); | |
|             } | |
| 
 | |
|             variable0_generated = true; | |
|          } | |
|          else | |
|          { | |
|             if (symbol_table_.is_variable(var0_name)) | |
|             { | |
|                variable0 = symbol_table_.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_, | |
|                              "ERR148 - 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(), | |
|                            "ERR149 - 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,false)) | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR150 - 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_, | |
|                              "ERR151 - 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 (symbol_table_.is_variable(var1_name)) | |
|             { | |
|                variable1 = symbol_table_.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_, | |
|                              "ERR152 - 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_, | |
|                           "ERR153 - 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); | |
| 
 | |
|          if ( | |
|               (0 != (v0 = dynamic_cast<variable_node_ptr>(variable0))) && | |
|               (0 != (v1 = dynamic_cast<variable_node_ptr>(variable1))) | |
|             ) | |
|          { | |
|             expression_node_ptr 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); | |
|             } | |
| 
 | |
|             return result; | |
|          } | |
|          else | |
|             return node_allocator_.allocate<details::swap_generic_node<T> >(variable0,variable1); | |
|       } | |
| 
 | |
|       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 (!commutative_check_enabled()) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR154 - 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; | |
| 
 | |
|          switch (token) | |
|          { | |
|             case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket   ,false) || | |
|                                                         token_is(token_t::e_lcrlbracket,false) || | |
|                                                         token_is(token_t::e_lsqrbracket,false) ; | |
|                                           break; | |
| 
 | |
|             case token_t::e_lbracket    : implied_mul = token_is(token_t::e_lbracket   ,false) || | |
|                                                         token_is(token_t::e_lcrlbracket,false) || | |
|                                                         token_is(token_t::e_lsqrbracket,false) ; | |
|                                           break; | |
| 
 | |
|             case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket   ,false) || | |
|                                                         token_is(token_t::e_lcrlbracket,false) || | |
|                                                         token_is(token_t::e_lsqrbracket,false) ; | |
|                                           break; | |
| 
 | |
|             default                     : return true; | |
|          } | |
| 
 | |
|          if (implied_mul) | |
|          { | |
|             if (!commutative_check_enabled()) | |
|             { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR155 - 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 = symbol_table_.get_variable(symbol); | |
| 
 | |
|          if (variable) | |
|          { | |
|             if (symbol_table_.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 or vector? | |
|          if (!sem_.empty()) | |
|          { | |
|             scope_element& se = sem_.get_element(symbol); | |
| 
 | |
|             if (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 | |
|          // Are we dealing with a string variable? | |
|          if (symbol_table_.is_stringvar(symbol)) | |
|          { | |
|             return parse_string(); | |
|          } | |
|          #endif | |
| 
 | |
|          { | |
|             // Are we dealing with a function? | |
|             ifunction<T>* function = symbol_table_.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_, | |
|                                 "ERR156 - Failed to generate node for function: '" + symbol + "'")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          { | |
|             // Are we dealing with a vararg function? | |
|             ivararg_function<T>* vararg_function = symbol_table_.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_, | |
|                                 "ERR157 - Failed to generate node for vararg function: '" + symbol + "'")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          { | |
|             // Are we dealing with a vararg generic function? | |
|             igeneric_function<T>* generic_function = symbol_table_.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_, | |
|                                 "ERR158 - Failed to generate node for generic function: '" + symbol + "'")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          { | |
|             // Are we dealing with a vararg string returing function? | |
|             igeneric_function<T>* string_function = symbol_table_.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_, | |
|                                 "ERR159 - Failed to generate node for string function: '" + symbol + "'")); | |
| 
 | |
|                   return error_node(); | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          // Are we dealing with a vector element? | |
|          if (symbol_table_.is_vector(symbol)) | |
|          { | |
|             lodge_symbol(symbol,e_st_vector); | |
|             return parse_vector(); | |
|          } | |
| 
 | |
|          if (details::is_reserved_symbol(symbol)) | |
|          { | |
|                set_error( | |
|                   make_error(parser_error::e_syntax, | |
|                              current_token_, | |
|                              "ERR160 - Invalid use of reserved symbol '" + symbol + "'")); | |
| 
 | |
|                return error_node(); | |
|          } | |
| 
 | |
|          // Should we handle unknown symbols? | |
|          if (resolve_unknown_symbol_ && unknown_symbol_resolver_) | |
|          { | |
|             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; | |
| 
 | |
|                switch (usr_symbol_type) | |
|                { | |
|                   case unknown_symbol_resolver::e_usr_variable_type : create_result = symbol_table_.create_variable(symbol,default_value); | |
|                                                                       break; | |
| 
 | |
|                   case unknown_symbol_resolver::e_usr_constant_type : create_result = symbol_table_.add_constant(symbol,default_value); | |
|                                                                       break; | |
| 
 | |
|                   default                                           : create_result = false; | |
|                } | |
| 
 | |
|                if (create_result) | |
|                { | |
|                   expression_node_ptr var = symbol_table_.get_variable(symbol); | |
| 
 | |
|                   if (var) | |
|                   { | |
|                      if (symbol_table_.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_, | |
|                              "ERR161 - Failed to create variable: '" + symbol + "'")); | |
| 
 | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          set_error( | |
|             make_error(parser_error::e_syntax, | |
|                        current_token_, | |
|                        "ERR162 - 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"    ; | |
| 
 | |
|          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)) | |
|          { | |
|             return parse_conditional_statement(); | |
|          } | |
|          else if (details::imatch(current_token_.value,symbol_while)) | |
|          { | |
|             return parse_while_loop(); | |
|          } | |
|          else if (details::imatch(current_token_.value,symbol_repeat)) | |
|          { | |
|             return parse_repeat_until_loop(); | |
|          } | |
|          else if (details::imatch(current_token_.value,symbol_for)) | |
|          { | |
|             return parse_for_loop(); | |
|          } | |
|          else if (details::imatch(current_token_.value,symbol_switch)) | |
|          { | |
|             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 (symbol_table_.valid() || !sem_.empty()) | |
|          { | |
|             return parse_symtab_symbol(); | |
|          } | |
|          else | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_symtab, | |
|                           current_token_, | |
|                           "ERR163 - 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_, | |
|                              "ERR164 - 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_, | |
|                              "ERR165 - 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_, | |
|                              "ERR166 - 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_, | |
|                              "ERR167 - 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_, | |
|                           "ERR168 - Premature end of expression[1]")); | |
| 
 | |
|             return error_node(); | |
|          } | |
|          else | |
|          { | |
|             set_error( | |
|                make_error(parser_error::e_syntax, | |
|                           current_token_, | |
|                           "ERR169 - Premature end of expression[2]")); | |
| 
 | |
|             return error_node(); | |
|          } | |
| 
 | |
|          if ( | |
|               branch                    && | |
|               (e_level00 == precedence) && | |
|               token_is(token_t::e_ternary,false) | |
|             ) | |
|          { | |
|             branch = parse_ternary_conditional_statement(branch); | |
|          } | |
| 
 | |
|          parse_pending_string_rangesize(branch); | |
| 
 | |
|          return branch; | |
|       } | |
| 
 | |
|       inline bool token_is(const typename token_t::token_type& ttype, const bool advance_token = true) | |
|       { | |
|          if (current_token_.type != ttype) | |
|          { | |
|             return false; | |
|          } | |
| 
 | |
|          if (advance_token) | |
|          { | |
|             next_token(); | |
|          } | |
| 
 | |
|          return true; | |
|       } | |
| 
 | |
|       inline bool peek_token_is(const typename token_t::token_type& ttype) | |
|       { | |
|          return (lexer_.peek_next_token().type == ttype); | |
|       } | |
| 
 | |
|       inline bool peek_token_is(const std::string& s) | |
|       { | |
|          return (details::imatch(lexer_.peek_next_token().value,s)); | |
|       } | |
| 
 | |
|       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); | |
|          } | |
| 
 | |
|          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(); | |
|          } | |
| 
 | |
|          inline bool unary_optimizable(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_optimizable(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_optimizable(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_optimizable(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_optimizable(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_optimizable(operation) && details::is_variable_node(branch[0])) | |
|                return synthesize_uv_expression(operation,branch); | |
|             else if (unary_optimizable(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) ; | |
|          } | |
| 
 | |
|          #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_optimizable(const details::operator_type& operation) const | |
|          { | |
|             return (details::e_add  == operation) || | |
|                    (details::e_sub  == operation) || | |
|                    (details::e_mul  == operation) || | |
|                    (details::e_div  == operation) || | |
|                    (details::e_mod  == operation) || | |
|                    (details::e_pow  == operation) || | |
|                    (details::e_lt   == operation) || | |
|                    (details::e_lte  == operation) || | |
|                    (details::e_gt   == operation) || | |
|                    (details::e_gte  == operation) || | |
|                    (details::e_eq   == operation) || | |
|                    (details::e_ne   == operation) || | |
|                    (details::e_and  == operation) || | |
|                    (details::e_nand == operation) || | |
|                    (details::e_or   == operation) || | |
|                    (details::e_nor  == operation) || | |
|                    (details::e_xor  == operation) || | |
|                    (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_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool cocob_optimizable(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_optimizable(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_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(operation)) | |
|                return false; | |
|             else | |
|                return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); | |
|          } | |
| 
 | |
|          inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const | |
|          { | |
|             if (!operation_optimizable(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_vector_node     (branch[0]) | |
|                          ) | |
|                          || b1_is_genstring; | |
|             } | |
|             else | |
|                return false; | |
|          } | |
| 
 | |
|          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_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) | |
|                       ); | |
|          } | |
| 
 | |
|          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_operation(operation,branch)) | |
|                return synthesize_veceqineq_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); | |
| 
 | |
|             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_optimizable(operation,branch)) | |
|                   result = synthesize_cocob_expression::process(*this,operation,branch); | |
|                else if (coboc_optimizable(operation,branch) && (0 == result)) | |
|                   result = synthesize_coboc_expression::process(*this,operation,branch); | |
| 
 | |
|                if (result) | |
|                   return result; | |
|             } | |
| 
 | |
|             if (uvouv_optimizable(operation,branch)) | |
|                return synthesize_uvouv_expression(operation,branch); | |
|             else if (vob_optimizable(operation,branch)) | |
|                return synthesize_vob_expression::process(*this,operation,branch); | |
|             else if (bov_optimizable(operation,branch)) | |
|                return synthesize_bov_expression::process(*this,operation,branch); | |
|             else if (cob_optimizable(operation,branch)) | |
|                return synthesize_cob_expression::process(*this,operation,branch); | |
|             else if (boc_optimizable(operation,branch)) | |
|                return synthesize_boc_expression::process(*this,operation,branch); | |
|             #ifndef exprtk_disable_enhanced_features | |
|             else if (cov_optimizable(operation,branch)) | |
|                return synthesize_cov_expression::process(*this,operation,branch); | |
|             #endif | |
|             else if (binext_optimizable(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 (&branch)[5]) | |
|          { | |
|             return synthesize_expression<quinary_node_t,5>(operation,branch); | |
|          } | |
| 
 | |
|          inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[6]) | |
|          { | |
|             return synthesize_expression<senary_node_t,6>(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 optimize. | |
|             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); | |
|          } | |
| 
 | |
|          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_optimize_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_optimize_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; | |
|          } | |
| 
 | |
|          template <typename Allocator, | |
|                    template <typename,typename> class Sequence> | |
|          inline expression_node_ptr 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_optimize_switch(arg_list); | |
|             else | |
|                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_optimize_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_optimize_sf3(const details::operator_type& operation, | |
|                                                        expression_node_ptr (&branch)[3]) | |
|          { | |
|             expression_node_ptr temp_node = error_node(); | |
| 
 | |
|             switch (operation) | |
|             { | |
|                #define case_stmt(op0,op1)                                  \ | |
|                case op0 : temp_node = node_allocator_->                    \ | |
|                              allocate<details::sf3_node<Type,op1<Type> > > \ | |
|                                 (operation,branch);                        \ | |
|                           break;                                           \ | |
| 
 | |
|                case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) | |
|                case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) | |
|                case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) | |
|                case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) | |
|                case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) | |
|                case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) | |
|                case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) | |
|                case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) | |
|                case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) | |
|                case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) | |
|                case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) | |
|                case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) | |
|                case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) | |
|                case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) | |
|                case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) | |
|                case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) | |
|                case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) | |
|                case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) | |
|                case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) | |
|                case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) | |
|                case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) | |
|                case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) | |
|                case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) | |
|                case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) | |
|                #undef case_stmt | |
|                default : return error_node(); | |
|             } | |
| 
 | |
|             T v = temp_node->value(); | |
|             node_allocator_->free(temp_node); | |
|             details::free_node(*node_allocator_,temp_node); | |
| 
 | |
|             return node_allocator_->allocate<literal_node_t>(v); | |
|          } | |
| 
 | |
|          inline expression_node_ptr varnode_optimize_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(op0,op1)                                          \ | |
|                case op0 : return node_allocator_->                                 \ | |
|                              allocate_rrr<details::sf3_var_node<Type,op1<Type> > > \ | |
|                                 (v0,v1,v2);                                        \ | |
| 
 | |
|                case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) | |
|                case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) | |
|                case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) | |
|                case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) | |
|                case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) | |
|                case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) | |
|                case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) | |
|                case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) | |
|                case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) | |
|                case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) | |
|                case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) | |
|                case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) | |
|                case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) | |
|                case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) | |
|                case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) | |
|                case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) | |
|                case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) | |
|                case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) | |
|                case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) | |
|                case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) | |
|                case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) | |
|                case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) | |
|                case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) | |
|                case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) | |
|                #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_optimize_sf3(operation,branch); | |
|             else if (all_nodes_variables(branch)) | |
|                return varnode_optimize_sf3(operation,branch); | |
|             else | |
|             { | |
|                switch (operation) | |
|                { | |
|                   #define case_stmt(op0,op1)                                                     \ | |
|                   case op0 : return node_allocator_->                                            \ | |
|                                 allocate<details::sf3_node<Type,op1<Type> > >(operation,branch); \ | |
| 
 | |
|                   case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) | |
|                   case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) | |
|                   case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) | |
|                   case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) | |
|                   case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) | |
|                   case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) | |
|                   case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) | |
|                   case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) | |
|                   case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) | |
|                   case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) | |
|                   case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) | |
|                   case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) | |
|                   case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) | |
|                   case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) | |
|                   case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) | |
|                   case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) | |
|                   case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) | |
|                   case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) | |
|                   case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) | |
|                   case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) | |
|                   case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) | |
|                   case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) | |
|                   case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) | |
|                   case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) | |
|                   #undef case_stmt | |
|                   default : return error_node(); | |
|                } | |
|             } | |
|          } | |
| 
 | |
|          inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) | |
|          { | |
|             expression_node_ptr temp_node = error_node(); | |
| 
 | |
|             switch (operation) | |
|             { | |
|                #define case_stmt(op0,op1)                                                                 \ | |
|                case op0 : temp_node = node_allocator_->                                                   \ | |
|                                          allocate<details::sf4_node<Type,op1<Type> > >(operation,branch); \ | |
|                           break;                                                                          \ | |
| 
 | |
|                case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) | |
|                case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) | |
|                case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) | |
|                case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) | |
|                case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) | |
|                case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) | |
|                case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) | |
|                case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) | |
|                case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) | |
|                case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) | |
|                case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) | |
|                case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) | |
|                case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) | |
|                case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) | |
|                case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) | |
|                case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) | |
|                case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) | |
|                case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) | |
|                case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) | |
|                case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) | |
|                case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) | |
|                case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) | |
|                case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) | |
|                case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) | |
|                case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) | |
|                case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_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 expression_node_ptr varnode_optimize_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(op0,op1)                                                         \ | |
|                case op0 : return node_allocator_->                                                \ | |
|                              allocate_rrrr<details::sf4_var_node<Type,op1<Type> > >(v0,v1,v2,v3); \ | |
| 
 | |
|                case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) | |
|                case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) | |
|                case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) | |
|                case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) | |
|                case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) | |
|                case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) | |
|                case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) | |
|                case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) | |
|                case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) | |
|                case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) | |
|                case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) | |
|                case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) | |
|                case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) | |
|                case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) | |
|                case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) | |
|                case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) | |
|                case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) | |
|                case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) | |
|                case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) | |
|                case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) | |
|                case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) | |
|                case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) | |
|                case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) | |
|                case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) | |
|                case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) | |
|                case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) | |
|                #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_optimize_sf4(operation,branch); | |
|             else if (all_nodes_variables(branch)) | |
|                return varnode_optimize_sf4(operation,branch); | |
|             switch (operation) | |
|             { | |
|                #define case_stmt(op0,op1)                                                     \ | |
|                case op0 : return node_allocator_->                                            \ | |
|                              allocate<details::sf4_node<Type,op1<Type> > >(operation,branch); \ | |
| 
 | |
|                case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) | |
|                case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) | |
|                case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) | |
|                case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) | |
|                case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) | |
|                case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) | |
|                case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) | |
|                case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) | |
|                case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) | |
|                case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) | |
|                case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) | |
|                case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) | |
|                case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) | |
|                case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) | |
|                case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) | |
|                case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) | |
|                case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) | |
|                case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) | |
|                case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) | |
|                case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) | |
|                case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) | |
|                case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) | |
|                case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) | |
|                case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) | |
|                case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) | |
|                case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) | |
|                #undef case_stmt | |
|                default : return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          template <typename Allocator, | |
|                    template <typename,typename> class Sequence> | |
|          inline expression_node_ptr const_optimize_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_optimize_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_optimize_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_optimize_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 optimized? | |
|                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); | |
|             } | |
| 
 | |
|             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>(gf,arg_list); | |
|             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()) | |
|                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()) | |
|                return result; | |
|             else | |
|             { | |
|                details::free_node(*node_allocator_,result); | |
|                details::free_all_nodes(*node_allocator_,arg_list); | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          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); | |
|                Type* v = (*vector_base)[i]; | |
| 
 | |
|                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.type     = scope_element::e_vecelem; | |
|                   nse.index    = i; | |
|                   nse.depth    = parser_->scope_depth_; | |
|                   nse.data     = 0; | |
|                   nse.var_node = new variable_node_t((*v)); | |
| 
 | |
|                   if (!parser_->sem_.add_element(nse)) | |
|                   { | |
|                      parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); | |
|                      result = error_node(); | |
|                   } | |
|                   else | |
|                      exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); | |
| 
 | |
|                   result = nse.var_node; | |
|                } | |
|             } | |
|             else | |
|                result = node_allocator_->allocate<details::vector_elem_node<Type> >(index,(*vector_base)[0]); | |
| 
 | |
|             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) | |
|          { | |
|             if (!parser_->dec_.collect_assignments()) | |
|                return; | |
| 
 | |
|             std::string symbol_name; | |
| 
 | |
|             switch (cst) | |
|             { | |
|                case e_st_variable : symbol_name = parser_->symbol_table_ | |
|                                                      .get_variable_name(node); | |
|                                     break; | |
| 
 | |
|                case e_st_string   : symbol_name = parser_->symbol_table_ | |
|                                                      .get_stringvar_name(node); | |
|                                     break; | |
| 
 | |
|                case e_st_vector   : { | |
|                                        typedef details::vector_holder<T> vector_holder_t; | |
| 
 | |
|                                        vector_holder_t& vh = static_cast<vector_node_t*>(node)->ref(); | |
| 
 | |
|                                        symbol_name = parser_->symbol_table_.get_vector_name(&vh); | |
|                                     } | |
|                                     break; | |
| 
 | |
|                default            : return; | |
|             } | |
| 
 | |
|             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])) | |
|                return synthesize_expression<assignment_vec_elem_node_t,2>(operation,branch); | |
|             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); | |
|             } | |
|             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_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(); | |
|                   } | |
|                } | |
|             } | |
|             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); | |
|             } | |
|             else | |
|             { | |
|                parser_->set_synthesis_error("Invalid assignment operation[2]"); | |
| 
 | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          inline expression_node_ptr synthesize_veceqineq_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]); | |
| 
 | |
|             if (is_b0_ivec && is_b1_ivec) | |
|             { | |
|                switch (operation) | |
|                { | |
|                   #define case_stmt(op0,op1)                                                                  \ | |
|                   case op0 : return node_allocator_->                                                         \ | |
|                                 template allocate_rrr<typename details::eqineq_vecvec_node<Type,op1<Type> > > \ | |
|                                    (operation,branch[0],branch[1]);                                           \ | |
| 
 | |
|                   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) | |
|                   #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::eqineq_vecval_node<Type,op1<Type> > > \ | |
|                                    (operation,branch[0],branch[1]);                                           \ | |
| 
 | |
|                   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) | |
|                   #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::eqineq_valvec_node<Type,op1<Type> > > \ | |
|                                    (operation,branch[0],branch[1]);                                           \ | |
| 
 | |
|                   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) | |
|                   #undef case_stmt | |
|                   default : return error_node(); | |
|                } | |
|             } | |
|             else | |
|                return error_node(); | |
|          } | |
| 
 | |
|          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::vecarith_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::vecarith_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::vecarith_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]); | |
| 
 | |
|             const bool v0_is_str = details::is_generally_string_node(branch[0]); | |
|             const bool v1_is_str = details::is_generally_string_node(branch[1]); | |
| 
 | |
|             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]))) | |
|                   ) | |
|                { | |
|                   return node_allocator_->allocate<details::swap_node<T> >(v0,v1); | |
|                } | |
|                else | |
|                   return node_allocator_->allocate<details::swap_generic_node<T> >(branch[0],branch[1]); | |
|             } | |
|             else if (v0_is_ivec && v1_is_ivec) | |
|             { | |
|                return node_allocator_->allocate<details::swap_vecvec_node<T> >(branch[0],branch[1]); | |
|             } | |
|             else if (v0_is_str && v1_is_str) | |
|             { | |
|                return node_allocator_->allocate<details::swap_string_node<T> >(branch[0],branch[1]); | |
|             } | |
|             else | |
|             { | |
|                parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); | |
| 
 | |
|                return error_node(); | |
|             } | |
|          } | |
| 
 | |
|          #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 <template <typename,typename> class IPowNode> | |
|          inline expression_node_ptr cardinal_pow_optimization_impl(const T& 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_optimization(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_optimization_impl<details::ipow_node>(v,p); | |
|                else | |
|                   return cardinal_pow_optimization_impl<details::ipowinv_node>(v,p); | |
|             } | |
|          } | |
| 
 | |
|          inline bool cardinal_pow_optimizable(const details::operator_type& operation, const T& c) | |
|          { | |
|             return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); | |
|          } | |
|          #else | |
|          inline expression_node_ptr cardinal_pow_optimization(T&, const T&) | |
|          { | |
|             return error_node(); | |
|          } | |
| 
 | |
|          inline bool cardinal_pow_optimizable(const details::operator_type&, const T&) | |
|          { | |
|             return false; | |
|          } | |
|          #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])) | |
|                   { | |
|                      details::operator_type o = static_cast<details::uv_base_node<Type>*>(branch[1])->operation(); | |
| 
 | |
|                      if (details::e_neg == o) | |
|                      { | |
|                         const Type& v1 = static_cast<details::uv_base_node<Type>*>(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])) | |
|                   { | |
|                      details::operator_type o = static_cast<details::uv_base_node<Type>*>(branch[0])->operation(); | |
| 
 | |
|                      if (details::e_neg == o) | |
|                      { | |
|                         const Type& v0 = static_cast<details::uv_base_node<Type>*>(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 (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 (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; | |
|                      } | |
|                   } | |
|                } | |
| 
 | |
|                #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(); | |
| 
 | |
|                   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 (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_optimizable(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]); | |
| 
 | |
|                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_optimizable(operation,c)) | |
|                { | |
|                   if (std::equal_to<T>()(T(1),c)) | |
|                      return branch[0]; | |
|                   else | |
|                      return expr_gen.cardinal_pow_optimization(v,c); | |
|                } | |
| 
 | |
|                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(op0,op1)                                          \ | |
|                   case op0 : return details::T0oT1oT2_sf3ext<T,T0,T1,T2,op1<Type> >:: \ | |
|                                 allocate(*(expr_gen.node_allocator_),t0,t1,t2);       \ | |
| 
 | |
|                   case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) | |
|                   case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) | |
|                   case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) | |
|                   case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) | |
|                   case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) | |
|                   case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) | |
|                   case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) | |
|                   case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) | |
|                   case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) | |
|                   case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) | |
|                   case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) | |
|                   case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) | |
|                   case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) | |
|                   case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) | |
|                   case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) | |
|                   case_stmt(details::e_sf30,details::sf30_op) | |
|                   #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_optimizable(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_stmt(op0,op1)                                                   \ | |
|                   case op0 : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,op1<Type> >:: \ | |
|                                 allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3);             \ | |
| 
 | |
|                   case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) | |
|                   case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) | |
|                   case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) | |
|                   case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) | |
|                   case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) | |
|                   case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) | |
|                   case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) | |
|                   case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) | |
|                   case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) | |
|                   case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) | |
|                   case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) | |
|                   case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) | |
|                   case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) | |
|                   case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) | |
|                   case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) | |
|                   case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) | |
|                   case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) | |
|                   case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) | |
|                   case_stmt(details::e_sf4ext00,details::sfext00_op) case_stmt(details::e_sf4ext01,details::sfext01_op) | |
|                   case_stmt(details::e_sf4ext02,details::sfext02_op) case_stmt(details::e_sf4ext03,details::sfext03_op) | |
|                   case_stmt(details::e_sf4ext04,details::sfext04_op) case_stmt(details::e_sf4ext05,details::sfext05_op) | |
|                   case_stmt(details::e_sf4ext06,details::sfext06_op) case_stmt(details::e_sf4ext07,details::sfext07_op) | |
|                   case_stmt(details::e_sf4ext08,details::sfext08_op) case_stmt(details::e_sf4ext09,details::sfext09_op) | |
|                   case_stmt(details::e_sf4ext10,details::sfext10_op) case_stmt(details::e_sf4ext11,details::sfext11_op) | |
|                   case_stmt(details::e_sf4ext12,details::sfext12_op) case_stmt(details::e_sf4ext13,details::sfext13_op) | |
|                   case_stmt(details::e_sf4ext14,details::sfext14_op) case_stmt(details::e_sf4ext15,details::sfext15_op) | |
|                   case_stmt(details::e_sf4ext16,details::sfext16_op) case_stmt(details::e_sf4ext17,details::sfext17_op) | |
|                   case_stmt(details::e_sf4ext18,details::sfext18_op) case_stmt(details::e_sf4ext19,details::sfext19_op) | |
|                   case_stmt(details::e_sf4ext20,details::sfext20_op) case_stmt(details::e_sf4ext21,details::sfext21_op) | |
|                   case_stmt(details::e_sf4ext22,details::sfext22_op) case_stmt(details::e_sf4ext23,details::sfext23_op) | |
|                   case_stmt(details::e_sf4ext24,details::sfext24_op) case_stmt(details::e_sf4ext25,details::sfext25_op) | |
|                   case_stmt(details::e_sf4ext26,details::sfext26_op) case_stmt(details::e_sf4ext27,details::sfext27_op) | |
|                   case_stmt(details::e_sf4ext28,details::sfext28_op) case_stmt(details::e_sf4ext29,details::sfext29_op) | |
|                   case_stmt(details::e_sf4ext30,details::sfext30_op) case_stmt(details::e_sf4ext31,details::sfext31_op) | |
|                   case_stmt(details::e_sf4ext32,details::sfext32_op) case_stmt(details::e_sf4ext33,details::sfext33_op) | |
|                   case_stmt(details::e_sf4ext34,details::sfext34_op) case_stmt(details::e_sf4ext35,details::sfext35_op) | |
|                   case_stmt(details::e_sf4ext36,details::sfext36_op) case_stmt(details::e_sf4ext37,details::sfext37_op) | |
|                   case_stmt(details::e_sf4ext38,details::sfext38_op) case_stmt(details::e_sf4ext39,details::sfext39_op) | |
|                   case_stmt(details::e_sf4ext40,details::sfext40_op) case_stmt(details::e_sf4ext41,details::sfext41_op) | |
|                   case_stmt(details::e_sf4ext42,details::sfext42_op) case_stmt(details::e_sf4ext43,details::sfext43_op) | |
|                   case_stmt(details::e_sf4ext44,details::sfext44_op) case_stmt(details::e_sf4ext45,details::sfext45_op) | |
|                   case_stmt(details::e_sf4ext46,details::sfext46_op) case_stmt(details::e_sf4ext47,details::sfext47_op) | |
|                   case_stmt(details::e_sf4ext48,details::sfext48_op) case_stmt(details::e_sf4ext49,details::sfext49_op) | |
|                   case_stmt(details::e_sf4ext50,details::sfext50_op) case_stmt(details::e_sf4ext51,details::sfext51_op) | |
|                   case_stmt(details::e_sf4ext52,details::sfext52_op) case_stmt(details::e_sf4ext53,details::sfext53_op) | |
|                   case_stmt(details::e_sf4ext54,details::sfext54_op) case_stmt(details::e_sf4ext55,details::sfext55_op) | |
|                   case_stmt(details::e_sf4ext56,details::sfext56_op) case_stmt(details::e_sf4ext57,details::sfext57_op) | |
|                   case_stmt(details::e_sf4ext58,details::sfext58_op) case_stmt(details::e_sf4ext59,details::sfext59_op) | |
| 
 | |
|                   #undef case_stmt | |
|                   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_optimizable(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.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.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.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.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.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.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.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.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.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.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.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.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); | |
|                   } | |
|                } | |
| 
 | |
|                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.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(); | |
|                   } | |
|                } | |
| 
 | |
|                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.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.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.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.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.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.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<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,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.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.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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covoc_t; | |
| 
 | |
|                const covoc_t* covoc = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 cocov_t; | |
| 
 | |
|                const cocov_t* cocov = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covoc_t; | |
| 
 | |
|                const covoc_t* covoc = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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 covoc_t; | |
| 
 | |
|                const covoc_t* covoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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 vococ_t; | |
| 
 | |
|                const vococ_t* vococ = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovov_t; | |
| 
 | |
|                const vovov_t* vovov = static_cast<const 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 vovoc_t; | |
| 
 | |
|                const vovoc_t* vovoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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 covoc_t; | |
| 
 | |
|                const covoc_t* covoc = static_cast<const 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 vocov_t; | |
| 
 | |
|                const vocov_t* vocov = static_cast<const 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 covov_t; | |
| 
 | |
|                const covov_t* covov = static_cast<const 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]) ; | |
| 
 | |
|             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]) ; | |
| 
 | |
|             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 optimization. | |
|                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 optimization. | |
| 
 | |
|             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); | |
|             } | |
|             else | |
|                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); | |
|                } | |
|             } | |
|             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,true); | |
|                } | |
|             } | |
| 
 | |
|             se.var_node  = 0; | |
|             se.vec_node  = 0; | |
|             se.data      = 0; | |
|             se.ref_count = 0; | |
|             se.active    = false; | |
|          } | |
|       } | |
| 
 | |
|       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) | |
|          #undef register_sf4ext | |
|       } | |
| 
 | |
|    private: | |
| 
 | |
|       parser(const parser<T>&); | |
|       parser<T>& operator=(const parser<T>&); | |
| 
 | |
|       lexer::generator lexer_; | |
|       lexer::token current_token_; | |
|       lexer::token store_current_token_; | |
|       expression_generator<T> expression_generator_; | |
|       details::node_allocator node_allocator_; | |
|       symbol_table_t symbol_table_; | |
|       dependent_entity_collector dec_; | |
|       std::size_t compile_options_; | |
|       std::deque<parser_error::type> error_list_; | |
|       std::deque<bool> brkcnt_list_; | |
|       bool resolve_unknown_symbol_; | |
|       bool vardef_disabled_; | |
|       std::size_t scope_depth_; | |
|       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(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(expression<T>& e, | |
|                       const std::string& variable_name, | |
|                       const T& r0, const T& r1, | |
|                       const std::size_t number_of_intervals = 1000000) | |
|    { | |
|       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(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(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(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(expression<T>& e, | |
|                        const std::string& variable_name, | |
|                        const T& h = T(0.00000001)) | |
|    { | |
|       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(expression<T>& e, | |
|                               const std::string& variable_name, | |
|                               const T& h = T(0.00001)) | |
|    { | |
|       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(expression<T>& e, | |
|                              const std::string& variable_name, | |
|                              const T& h = T(0.0001)) | |
|    { | |
|       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: | |
| 
 | |
|       polynomial() | |
|       : exprtk::ifunction<T>((N+2 <= 20) ? (N + 2) : std::numeric_limits<std::size_t>::max(),false) | |
|       {} | |
| 
 | |
|       inline virtual T operator()(const T& x, const T& c1, const T& c0) | |
|       { | |
|          return ((1 == N) ? poly_impl<T,1>::evaluate(x,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) | |
|       { | |
|          return ((2 == N) ? poly_impl<T,2>::evaluate(x,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) | |
|       { | |
|          return ((3 == N) ? poly_impl<T,3>::evaluate(x,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) | |
|       { | |
|          return ((4 == N) ? poly_impl<T,4>::evaluate(x,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((5 == N) ? poly_impl<T,5>::evaluate(x,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((6 == N) ? poly_impl<T,6>::evaluate(x,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((7 == N) ? poly_impl<T,7>::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((8 == N) ? poly_impl<T,8>::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((9 == N) ? poly_impl<T,9>::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((10 == N) ? poly_impl<T,10>::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((11 == N) ? poly_impl<T,11>::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return ((12 == N) ? poly_impl<T,12>::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN()); | |
|       } | |
| 
 | |
|       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; | |
| 
 | |
|       struct function | |
|       { | |
|          function() | |
|          {} | |
| 
 | |
|          function(const std::string& n) | |
|          : name_(n) | |
|          {} | |
| 
 | |
|          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; | |
| 
 | |
|          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::expression_holder::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; | |
|             } | |
|          } | |
| 
 | |
|          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 | |
|       { | |
|          func_0param() : base_func(0) {} | |
| 
 | |
|          inline T operator()() | |
|          { | |
|             return base_func::expression.value(); | |
|          } | |
|       }; | |
| 
 | |
|       typedef const T& type; | |
| 
 | |
|       struct func_1param : public base_func | |
|       { | |
|          func_1param() : base_func(1) {} | |
| 
 | |
|          inline T operator()(type v0) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       struct func_2param : public base_func | |
|       { | |
|          func_2param() : base_func(2) {} | |
| 
 | |
|          inline T operator()(type v0, type v1) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0,v1); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       struct func_3param : public base_func | |
|       { | |
|          func_3param() : base_func(3) {} | |
| 
 | |
|          inline T operator()(type v0, type v1, type v2) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0,v1,v2); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       struct func_4param : public base_func | |
|       { | |
|          func_4param() : base_func(4) {} | |
| 
 | |
|          inline T operator()(type v0, type v1, type v2, type v3) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0,v1,v2,v3); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       struct func_5param : public base_func | |
|       { | |
|          func_5param() : base_func(5) {} | |
| 
 | |
|          inline T operator()(type v0, type v1, type v2, type v3, type v4) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0,v1,v2,v3,v4); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       struct func_6param : public base_func | |
|       { | |
|          func_6param() : base_func(6) {} | |
| 
 | |
|          inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) | |
|          { | |
|             base_func::pre(); | |
|             base_func::update(v0,v1,v2,v3,v4,v5); | |
|             T result = base_func::expression.value(); | |
|             base_func::post(); | |
|             return result; | |
|          } | |
|       }; | |
| 
 | |
|       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 std::size_t n = var_list.size(); | |
| 
 | |
|          if (expr_map_.end() != expr_map_.find(name)) | |
|             return false; | |
|          else if (compile_expression(name,expression,var_list)) | |
|          { | |
|             fp_map_[n][name]->setup(expr_map_[name]); | |
|             return true; | |
|          } | |
|          else | |
|             return false; | |
|       } | |
| 
 | |
|    public: | |
| 
 | |
|       function_compositor() | |
|       : fp_map_(7) | |
|       {} | |
| 
 | |
|       function_compositor(const symbol_table_t& st) | |
|       : symbol_table_(st), | |
|         fp_map_(7) | |
|       {} | |
| 
 | |
|      ~function_compositor() | |
|       { | |
|          clear(); | |
|       } | |
| 
 | |
|       inline symbol_table_t& symbol_table() | |
|       { | |
|          return symbol_table_; | |
|       } | |
| 
 | |
|       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) | |
|       { | |
|          return add(f.name_,f.expression_,f.v_); | |
|       } | |
| 
 | |
|       inline bool add(const std::string& name, | |
|                       const std::string& expression) | |
|       { | |
|          const std::size_t n = 0; | |
|          std::vector<std::string> v(n); | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(const std::string& name, | |
|                       const std::string& expression, | |
|                       const std::string& v0) | |
|       { | |
|          const std::size_t n = 1; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(const std::string& name, | |
|                       const std::string& expression, | |
|                       const std::string& v0, const std::string& v1) | |
|       { | |
|          const std::size_t n = 2; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; v[1] = v1; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(const std::string& name, | |
|                       const std::string& expression, | |
|                       const std::string& v0, const std::string& v1, const std::string& v2) | |
|       { | |
|          const std::size_t n = 3; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; v[1] = v1; v[2] = v2; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(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::size_t n = 4; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; v[1] = v1; | |
|          v[2] = v2; v[3] = v3; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(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) | |
|       { | |
|          const std::size_t n = 5; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; v[1] = v1; | |
|          v[2] = v2; v[3] = v3; | |
|          v[4] = v4; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|       inline bool add(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, const std::string& v5) | |
|       { | |
|          const std::size_t n = 5; | |
|          std::vector<std::string> v(n); | |
|          v[0] = v0; v[1] = v1; | |
|          v[2] = v2; v[3] = v3; | |
|          v[4] = v4; v[5] = v5; | |
|          return add(name,expression,v); | |
|       } | |
| 
 | |
|    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) | |
|       { | |
|          expression_t compiled_expression; | |
|          symbol_table_t local_symbol_table; | |
| 
 | |
|          local_symbol_table.load_from(symbol_table_); | |
|          local_symbol_table.add_constants(); | |
| 
 | |
|          if (!forward(name,input_var_list.size(),local_symbol_table)) | |
|             return false; | |
| 
 | |
|          compiled_expression.register_symbol_table(local_symbol_table); | |
| 
 | |
|          std::string mod_expression; | |
| 
 | |
|          for (std::size_t i = 0; i < input_var_list.size(); ++i) | |
|          { | |
|             mod_expression += " var " + input_var_list[i] + "{};\n"; | |
|          } | |
| 
 | |
|          mod_expression += "~{" + expression + "};"; | |
| 
 | |
|          if (!parser_.compile(mod_expression,compiled_expression)) | |
|          { | |
|             exprtk_debug(("Error: %s\n",parser_.error().c_str())); | |
|             return false; | |
|          } | |
| 
 | |
|          expr_map_[name] = compiled_expression; | |
| 
 | |
|          exprtk::ifunction<T>& ifunc = (*(fp_map_[input_var_list.size()])[name]); | |
| 
 | |
|          return symbol_table_.add_function(name,ifunc); | |
|       } | |
| 
 | |
|       inline bool symbol_used(const std::string& symbol) | |
|       { | |
|          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 forward(const std::string& name, const std::size_t& arg_count, symbol_table_t& sym_table) | |
|       { | |
|          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; | |
| 
 | |
|             switch (arg_count) | |
|             { | |
|                case 0  : (fp_map_[arg_count])[name] = new func_0param(); break; | |
|                case 1  : (fp_map_[arg_count])[name] = new func_1param(); break; | |
|                case 2  : (fp_map_[arg_count])[name] = new func_2param(); break; | |
|                case 3  : (fp_map_[arg_count])[name] = new func_3param(); break; | |
|                case 4  : (fp_map_[arg_count])[name] = new func_4param(); break; | |
|                case 5  : (fp_map_[arg_count])[name] = new func_5param(); break; | |
|                case 6  : (fp_map_[arg_count])[name] = new func_6param(); break; | |
|             } | |
| 
 | |
|             exprtk::ifunction<T>& ifunc = (*(fp_map_[arg_count])[name]); | |
| 
 | |
|             return sym_table.add_function(name,ifunc); | |
|          } | |
|       } | |
| 
 | |
|       template <typename Allocator, | |
|                 template <typename,typename> class Sequence> | |
|       inline void remove(const std::string& name, const Sequence<std::string,Allocator>& v) | |
|       { | |
|          symbol_table_.remove_function(name); | |
| 
 | |
|          for (std::size_t i = 0; i < v.size(); ++i) | |
|          { | |
|             symbol_table_.remove_variable(v[i]); | |
|          } | |
| 
 | |
|          remove(name,v.size()); | |
|       } | |
| 
 | |
|       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) | |
|             return; | |
|          else | |
|             delete fp_itr->second; | |
| 
 | |
|          fp_map_[arg_count].erase(fp_itr); | |
|       } | |
| 
 | |
|    private: | |
| 
 | |
|       symbol_table_t symbol_table_; | |
|       parser_t parser_; | |
|       std::map<std::string,expression_t> expr_map_; | |
|       std::vector<funcparam_t> fp_map_; | |
|    }; | |
| 
 | |
|    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; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 2>::result(v),details::numeric::pow(v,T( 2))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 3>::result(v),details::numeric::pow(v,T( 3))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 4>::result(v),details::numeric::pow(v,T( 4))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 5>::result(v),details::numeric::pow(v,T( 5))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 6>::result(v),details::numeric::pow(v,T( 6))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 7>::result(v),details::numeric::pow(v,T( 7))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 8>::result(v),details::numeric::pow(v,T( 8))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 9>::result(v),details::numeric::pow(v,T( 9))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,10>::result(v),details::numeric::pow(v,T(10))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,11>::result(v),details::numeric::pow(v,T(11))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,12>::result(v),details::numeric::pow(v,T(12))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,13>::result(v),details::numeric::pow(v,T(13))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,14>::result(v),details::numeric::pow(v,T(14))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,15>::result(v),details::numeric::pow(v,T(15))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,16>::result(v),details::numeric::pow(v,T(16))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,17>::result(v),details::numeric::pow(v,T(17))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,18>::result(v),details::numeric::pow(v,T(18))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,19>::result(v),details::numeric::pow(v,T(19))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,20>::result(v),details::numeric::pow(v,T(20))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,21>::result(v),details::numeric::pow(v,T(21))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,22>::result(v),details::numeric::pow(v,T(22))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,23>::result(v),details::numeric::pow(v,T(23))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,24>::result(v),details::numeric::pow(v,T(24))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,25>::result(v),details::numeric::pow(v,T(25))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,26>::result(v),details::numeric::pow(v,T(26))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,27>::result(v),details::numeric::pow(v,T(27))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,28>::result(v),details::numeric::pow(v,T(28))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,29>::result(v),details::numeric::pow(v,T(29))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,30>::result(v),details::numeric::pow(v,T(30))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,31>::result(v),details::numeric::pow(v,T(31))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,32>::result(v),details::numeric::pow(v,T(32))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,33>::result(v),details::numeric::pow(v,T(33))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,34>::result(v),details::numeric::pow(v,T(34))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,35>::result(v),details::numeric::pow(v,T(35))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,36>::result(v),details::numeric::pow(v,T(36))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,37>::result(v),details::numeric::pow(v,T(37))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,38>::result(v),details::numeric::pow(v,T(38))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,39>::result(v),details::numeric::pow(v,T(39))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,40>::result(v),details::numeric::pow(v,T(40))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,41>::result(v),details::numeric::pow(v,T(41))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,42>::result(v),details::numeric::pow(v,T(42))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,43>::result(v),details::numeric::pow(v,T(43))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,44>::result(v),details::numeric::pow(v,T(44))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,45>::result(v),details::numeric::pow(v,T(45))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,46>::result(v),details::numeric::pow(v,T(46))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,47>::result(v),details::numeric::pow(v,T(47))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,48>::result(v),details::numeric::pow(v,T(48))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,49>::result(v),details::numeric::pow(v,T(49))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,50>::result(v),details::numeric::pow(v,T(50))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,51>::result(v),details::numeric::pow(v,T(51))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,52>::result(v),details::numeric::pow(v,T(52))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,53>::result(v),details::numeric::pow(v,T(53))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,54>::result(v),details::numeric::pow(v,T(54))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,55>::result(v),details::numeric::pow(v,T(55))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,56>::result(v),details::numeric::pow(v,T(56))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,57>::result(v),details::numeric::pow(v,T(57))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,58>::result(v),details::numeric::pow(v,T(58))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,59>::result(v),details::numeric::pow(v,T(59))))) return false; | |
|             else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,60>::result(v),details::numeric::pow(v,T(60))))) return false; | |
|          } | |
|       } | |
| 
 | |
|       return true; | |
|    } | |
| 
 | |
|    namespace helper | |
|    { | |
|       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; | |
| 
 | |
|             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]; | |
| 
 | |
|                   typename exprtk::details::numeric::details::number_type<T>::type num_type; | |
| 
 | |
|                   switch (gt.type) | |
|                   { | |
|                      case generic_type::e_scalar : print_type(scalar_format.c_str(),scalar_t(gt)(),num_type); | |
|                                                    break; | |
| 
 | |
|                      case generic_type::e_vector : { | |
|                                                       vector_t vector(gt); | |
| 
 | |
|                                                       for (std::size_t x = 0; x < vector.size(); ++x) | |
|                                                       { | |
|                                                          print_type(scalar_format.c_str(),vector[x],num_type); | |
| 
 | |
|                                                          if ((x + 1) < vector.size()) | |
|                                                             printf(" "); | |
|                                                       } | |
|                                                    } | |
|                                                    break; | |
| 
 | |
|                      case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str()); | |
|                                                    break; | |
| 
 | |
|                      default                     : continue; | |
|                   } | |
|                } | |
|             } | |
|          }; | |
|       } | |
| 
 | |
|       template <typename T> | |
|       struct print : public exprtk::igeneric_function<T> | |
|       { | |
|          typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; | |
| 
 | |
|          print(const std::string& scalar_format = "%10.5f") | |
|          : scalar_format_(scalar_format) | |
|          {} | |
| 
 | |
|          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; | |
| 
 | |
|          println(const std::string& scalar_format = "%10.5f") | |
|          : scalar_format_(scalar_format) | |
|          {} | |
| 
 | |
|          inline T operator()(parameter_list_t parameters) | |
|          { | |
|             details::print_impl<T>::process(scalar_format_,parameters); | |
|             printf("\n"); | |
|             return T(0); | |
|          } | |
| 
 | |
|          std::string scalar_format_; | |
|       }; | |
|    } | |
| } | |
| 
 | |
| #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 information | |
|    { | |
|       static const char* library = "Mathematical Expression Toolkit"; | |
|       static const char* version = "2.7182818284590452353602874713526624977572470936999595"; | |
|       static const char* date    = "20150111"; | |
| 
 | |
|       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
 |