+/*
+ ******************************************************************
+ * C++ Mathematical Expression Toolkit Library *
+ * *
+ * Author: Arash Partow (1999-2020) *
+ * 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 MIT License. *
+ * http://www.opensource.org/licenses/MIT *
+ * *
+ * Example expressions: *
+ * (00) (y + x / y) * (x - y / x) *
+ * (01) (x^2 / sin(2 * pi / y)) - x / 2 *
+ * (02) sqrt(1 - (x^2)) *
+ * (03) 1 - sin(2 * x) + cos(pi / y) *
+ * (04) a * exp(2 * t) + c *
+ * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) *
+ * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x *
+ * (07) z := x + sin(2 * pi / y) *
+ * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) *
+ * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) *
+ * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) *
+ * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) *
+ * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] *
+ * *
+ ******************************************************************
+*/
+
+
+#ifndef INCLUDE_EXPRTK_HPP
+#define INCLUDE_EXPRTK_HPP
+
+
+#include <algorithm>
+#include <cctype>
+#include <cmath>
+#include <complex>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <deque>
+#include <exception>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <list>
+#include <map>
+#include <set>
+#include <stack>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+
+namespace exprtk
+{
+ #ifdef exprtk_enable_debugging
+ #define exprtk_debug(params) printf params
+ #else
+ #define exprtk_debug(params) (void)0
+ #endif
+
+ #define exprtk_error_location \
+ "exprtk.hpp:" + details::to_str(__LINE__) \
+
+ #if defined(__GNUC__) && (__GNUC__ >= 7)
+
+ #define exprtk_disable_fallthrough_begin \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \
+
+ #define exprtk_disable_fallthrough_end \
+ _Pragma ("GCC diagnostic pop") \
+
+ #else
+ #define exprtk_disable_fallthrough_begin (void)0;
+ #define exprtk_disable_fallthrough_end (void)0;
+ #endif
+
+ namespace details
+ {
+ typedef unsigned char uchar_t;
+ typedef char char_t;
+ typedef uchar_t* uchar_ptr;
+ typedef char_t* char_ptr;
+ typedef uchar_t const* uchar_cptr;
+ typedef char_t const* char_cptr;
+ typedef unsigned long long int _uint64_t;
+ typedef long long int _int64_t;
+
+ inline bool is_whitespace(const char_t c)
+ {
+ return (' ' == c) || ('\n' == c) ||
+ ('\r' == c) || ('\t' == c) ||
+ ('\b' == c) || ('\v' == c) ||
+ ('\f' == c) ;
+ }
+
+ inline bool is_operator_char(const char_t c)
+ {
+ return ('+' == c) || ('-' == c) ||
+ ('*' == c) || ('/' == c) ||
+ ('^' == c) || ('<' == c) ||
+ ('>' == c) || ('=' == c) ||
+ (',' == c) || ('!' == c) ||
+ ('(' == c) || (')' == c) ||
+ ('[' == c) || (']' == c) ||
+ ('{' == c) || ('}' == c) ||
+ ('%' == c) || (':' == c) ||
+ ('?' == c) || ('&' == c) ||
+ ('|' == c) || (';' == c) ;
+ }
+
+ inline bool is_letter(const char_t c)
+ {
+ return (('a' <= c) && (c <= 'z')) ||
+ (('A' <= c) && (c <= 'Z')) ;
+ }
+
+ inline bool is_digit(const char_t c)
+ {
+ return ('0' <= c) && (c <= '9');
+ }
+
+ inline bool is_letter_or_digit(const char_t c)
+ {
+ return is_letter(c) || is_digit(c);
+ }
+
+ inline bool is_left_bracket(const char_t c)
+ {
+ return ('(' == c) || ('[' == c) || ('{' == c);
+ }
+
+ inline bool is_right_bracket(const char_t c)
+ {
+ return (')' == c) || (']' == c) || ('}' == c);
+ }
+
+ inline bool is_bracket(const char_t c)
+ {
+ return is_left_bracket(c) || is_right_bracket(c);
+ }
+
+ inline bool is_sign(const char_t c)
+ {
+ return ('+' == c) || ('-' == c);
+ }
+
+ inline bool is_invalid(const char_t c)
+ {
+ return !is_whitespace (c) &&
+ !is_operator_char(c) &&
+ !is_letter (c) &&
+ !is_digit (c) &&
+ ('.' != c) &&
+ ('_' != c) &&
+ ('$' != c) &&
+ ('~' != c) &&
+ ('\'' != c);
+ }
+
+ #ifndef exprtk_disable_caseinsensitivity
+ inline void case_normalise(std::string& s)
+ {
+ for (std::size_t i = 0; i < s.size(); ++i)
+ {
+ s[i] = static_cast<std::string::value_type>(std::tolower(s[i]));
+ }
+ }
+
+ inline bool imatch(const char_t c1, const char_t c2)
+ {
+ return std::tolower(c1) == std::tolower(c2);
+ }
+
+ inline bool imatch(const std::string& s1, const std::string& s2)
+ {
+ if (s1.size() == s2.size())
+ {
+ for (std::size_t i = 0; i < s1.size(); ++i)
+ {
+ if (std::tolower(s1[i]) != std::tolower(s2[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ struct ilesscompare
+ {
+ inline bool operator() (const std::string& s1, const std::string& s2) const
+ {
+ const std::size_t length = std::min(s1.size(),s2.size());
+
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ const char_t c1 = static_cast<char>(std::tolower(s1[i]));
+ const char_t c2 = static_cast<char>(std::tolower(s2[i]));
+
+ if (c1 > c2)
+ return false;
+ else if (c1 < c2)
+ return true;
+ }
+
+ return s1.size() < s2.size();
+ }
+ };
+
+ #else
+ inline void case_normalise(std::string&)
+ {}
+
+ inline bool imatch(const char_t c1, const char_t c2)
+ {
+ return c1 == c2;
+ }
+
+ inline bool imatch(const std::string& s1, const std::string& s2)
+ {
+ return s1 == s2;
+ }
+
+ struct ilesscompare
+ {
+ inline bool operator() (const std::string& s1, const std::string& s2) const
+ {
+ return s1 < s2;
+ }
+ };
+ #endif
+
+ inline bool is_valid_sf_symbol(const std::string& symbol)
+ {
+ // Special function: $f12 or $F34
+ return (4 == symbol.size()) &&
+ ('$' == symbol[0]) &&
+ imatch('f',symbol[1]) &&
+ is_digit(symbol[2]) &&
+ is_digit(symbol[3]);
+ }
+
+ inline const char_t& front(const std::string& s)
+ {
+ return s[0];
+ }
+
+ inline const char_t& back(const std::string& s)
+ {
+ return s[s.size() - 1];
+ }
+
+ inline std::string to_str(int i)
+ {
+ if (0 == i)
+ return std::string("0");
+
+ std::string result;
+
+ if (i < 0)
+ {
+ for ( ; i; i /= 10)
+ {
+ result += '0' + char(-(i % 10));
+ }
+
+ result += '-';
+ }
+ else
+ {
+ for ( ; i; i /= 10)
+ {
+ result += '0' + char(i % 10);
+ }
+ }
+
+ std::reverse(result.begin(), result.end());
+
+ return result;
+ }
+
+ inline std::string to_str(std::size_t i)
+ {
+ return to_str(static_cast<int>(i));
+ }
+
+ inline bool is_hex_digit(const std::string::value_type digit)
+ {
+ return (('0' <= digit) && (digit <= '9')) ||
+ (('A' <= digit) && (digit <= 'F')) ||
+ (('a' <= digit) && (digit <= 'f')) ;
+ }
+
+ inline uchar_t hex_to_bin(uchar_t h)
+ {
+ if (('0' <= h) && (h <= '9'))
+ return (h - '0');
+ else
+ return static_cast<unsigned char>(std::toupper(h) - 'A');
+ }
+
+ template <typename Iterator>
+ inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result)
+ {
+ if (
+ (end != (itr )) &&
+ (end != (itr + 1)) &&
+ (end != (itr + 2)) &&
+ (end != (itr + 3)) &&
+ ('0' == *(itr )) &&
+ (
+ ('x' == *(itr + 1)) ||
+ ('X' == *(itr + 1))
+ ) &&
+ (is_hex_digit(*(itr + 2))) &&
+ (is_hex_digit(*(itr + 3)))
+ )
+ {
+ result = hex_to_bin(static_cast<uchar_t>(*(itr + 2))) << 4 |
+ hex_to_bin(static_cast<uchar_t>(*(itr + 3))) ;
+ itr += 3;
+ }
+ else
+ result = '\0';
+ }
+
+ inline void cleanup_escapes(std::string& s)
+ {
+ typedef std::string::iterator str_itr_t;
+
+ str_itr_t itr1 = s.begin();
+ str_itr_t itr2 = s.begin();
+ str_itr_t end = s.end ();
+
+ std::size_t removal_count = 0;
+
+ while (end != itr1)
+ {
+ if ('\\' == (*itr1))
+ {
+ ++removal_count;
+
+ if (end == ++itr1)
+ break;
+ else if ('\\' != (*itr1))
+ {
+ switch (*itr1)
+ {
+ case 'n' : (*itr1) = '\n'; break;
+ case 'r' : (*itr1) = '\r'; break;
+ case 't' : (*itr1) = '\t'; break;
+ case '0' : parse_hex(itr1, end, (*itr1));
+ removal_count += 3;
+ break;
+ }
+
+ continue;
+ }
+ }
+
+ if (itr1 != itr2)
+ {
+ (*itr2) = (*itr1);
+ }
+
+ ++itr1;
+ ++itr2;
+ }
+
+ s.resize(s.size() - removal_count);
+ }
+
+ class build_string
+ {
+ public:
+
+ build_string(const std::size_t& initial_size = 64)
+ {
+ data_.reserve(initial_size);
+ }
+
+ inline build_string& operator << (const std::string& s)
+ {
+ data_ += s;
+ return (*this);
+ }
+
+ inline build_string& operator << (char_cptr 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_;
+ };
+
+ static const std::string reserved_words[] =
+ {
+ "break", "case", "continue", "default", "false", "for",
+ "if", "else", "ilike", "in", "like", "and", "nand", "nor",
+ "not", "null", "or", "repeat", "return", "shl", "shr",
+ "swap", "switch", "true", "until", "var", "while", "xnor",
+ "xor", "&", "|"
+ };
+
+ static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string);
+
+ static const std::string reserved_symbols[] =
+ {
+ "abs", "acos", "acosh", "and", "asin", "asinh", "atan",
+ "atanh", "atan2", "avg", "break", "case", "ceil", "clamp",
+ "continue", "cos", "cosh", "cot", "csc", "default",
+ "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp",
+ "expm1", "false", "floor", "for", "frac", "grad2deg",
+ "hypot", "iclamp", "if", "else", "ilike", "in", "inrange",
+ "like", "log", "log10", "log2", "logn", "log1p", "mand",
+ "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor",
+ "not", "not_equal", "null", "or", "pow", "rad2deg",
+ "repeat", "return", "root", "round", "roundn", "sec", "sgn",
+ "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap",
+ "switch", "tan", "tanh", "true", "trunc", "until", "var",
+ "while", "xnor", "xor", "&", "|"
+ };
+
+ static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string);
+
+ static const std::string base_function_list[] =
+ {
+ "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh",
+ "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot",
+ "csc", "equal", "erf", "erfc", "exp", "expm1", "floor",
+ "frac", "hypot", "iclamp", "like", "log", "log10", "log2",
+ "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul",
+ "ncdf", "pow", "root", "round", "roundn", "sec", "sgn",
+ "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh",
+ "trunc", "not_equal", "inrange", "deg2grad", "deg2rad",
+ "rad2deg", "grad2deg"
+ };
+
+ static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string);
+
+ static const std::string logic_ops_list[] =
+ {
+ "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|"
+ };
+
+ static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string);
+
+ static const std::string cntrl_struct_list[] =
+ {
+ "if", "switch", "for", "while", "repeat", "return"
+ };
+
+ static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string);
+
+ static const std::string arithmetic_ops_list[] =
+ {
+ "+", "-", "*", "/", "%", "^"
+ };
+
+ static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string);
+
+ static const std::string assignment_ops_list[] =
+ {
+ ":=", "+=", "-=",
+ "*=", "/=", "%="
+ };
+
+ static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string);
+
+ static const std::string inequality_ops_list[] =
+ {
+ "<", "<=", "==",
+ "=", "!=", "<>",
+ ">=", ">"
+ };
+
+ static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string);
+
+ inline bool is_reserved_word(const std::string& symbol)
+ {
+ for (std::size_t i = 0; i < reserved_words_size; ++i)
+ {
+ if (imatch(symbol, reserved_words[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ inline bool is_reserved_symbol(const std::string& symbol)
+ {
+ for (std::size_t i = 0; i < reserved_symbols_size; ++i)
+ {
+ if (imatch(symbol, reserved_symbols[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ inline bool is_base_function(const std::string& function_name)
+ {
+ for (std::size_t i = 0; i < base_function_list_size; ++i)
+ {
+ if (imatch(function_name, base_function_list[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ inline bool is_control_struct(const std::string& cntrl_strct)
+ {
+ for (std::size_t i = 0; i < cntrl_struct_list_size; ++i)
+ {
+ if (imatch(cntrl_strct, cntrl_struct_list[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ inline bool is_logic_opr(const std::string& lgc_opr)
+ {
+ for (std::size_t i = 0; i < logic_ops_list_size; ++i)
+ {
+ if (imatch(lgc_opr, logic_ops_list[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ struct cs_match
+ {
+ static inline bool cmp(const char_t c0, const char_t c1)
+ {
+ return (c0 == c1);
+ }
+ };
+
+ struct cis_match
+ {
+ static inline bool cmp(const char_t c0, const char_t c1)
+ {
+ return (std::tolower(c0) == std::tolower(c1));
+ }
+ };
+
+ template <typename Iterator, typename Compare>
+ inline bool match_impl(const Iterator pattern_begin,
+ const Iterator pattern_end ,
+ const Iterator data_begin ,
+ const Iterator data_end ,
+ const typename std::iterator_traits<Iterator>::value_type& zero_or_more,
+ const typename std::iterator_traits<Iterator>::value_type& zero_or_one )
+ {
+ const Iterator null_itr(0);
+
+ Iterator d_itr = data_begin;
+ Iterator p_itr = pattern_begin;
+ Iterator tb_p_itr = null_itr;
+ Iterator tb_d_itr = null_itr;
+
+ while (d_itr != data_end)
+ {
+ if (zero_or_more == *p_itr)
+ {
+ while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
+ {
+ ++p_itr;
+ }
+
+ if (pattern_end == p_itr)
+ return true;
+
+ const typename std::iterator_traits<Iterator>::value_type c = *(p_itr);
+
+ while ((data_end != d_itr) && !Compare::cmp(c,*d_itr))
+ {
+ ++d_itr;
+ }
+
+ tb_p_itr = p_itr;
+ tb_d_itr = d_itr;
+
+ continue;
+ }
+ else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr))
+ {
+ if (null_itr == tb_d_itr)
+ return false;
+
+ d_itr = tb_d_itr++;
+ p_itr = tb_p_itr;
+
+ continue;
+ }
+
+ ++p_itr;
+ ++d_itr;
+ }
+
+ while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
+ {
+ ++p_itr;
+ }
+
+ return (pattern_end == p_itr);
+ }
+
+ inline bool wc_match(const std::string& wild_card,
+ const std::string& str)
+ {
+ return match_impl<char_cptr,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<char_cptr,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_t& diff_value)
+ {
+ if (str.empty())
+ {
+ return ("Z" == pattern);
+ }
+ else if ('*' == pattern[0])
+ return false;
+
+ typedef std::string::const_iterator itr_t;
+
+ itr_t p_itr = pattern.begin();
+ itr_t s_itr = str .begin();
+
+ itr_t p_end = pattern.end();
+ itr_t s_end = str .end();
+
+ while ((s_end != s_itr) && (p_end != p_itr))
+ {
+ if ('*' == (*p_itr))
+ {
+ const char_t target = static_cast<char>(std::toupper(*(p_itr - 1)));
+
+ if ('*' == target)
+ {
+ diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr));
+ diff_value = static_cast<char>(std::toupper(*p_itr));
+
+ return false;
+ }
+ else
+ ++p_itr;
+
+ while (s_itr != s_end)
+ {
+ if (target != std::toupper(*s_itr))
+ break;
+ else
+ ++s_itr;
+ }
+
+ continue;
+ }
+ else if (
+ ('?' != *p_itr) &&
+ std::toupper(*p_itr) != std::toupper(*s_itr)
+ )
+ {
+ diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr));
+ diff_value = static_cast<char>(std::toupper(*p_itr));
+
+ return false;
+ }
+
+ ++p_itr;
+ ++s_itr;
+ }
+
+ return (
+ (s_end == s_itr) &&
+ (
+ (p_end == p_itr) ||
+ ('*' == *p_itr)
+ )
+ );
+ }
+
+ static const double pow10[] = {
+ 1.0,
+ 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004,
+ 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008,
+ 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012,
+ 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016
+ };
+
+ static const std::size_t pow10_size = sizeof(pow10) / sizeof(double);
+
+ namespace numeric
+ {
+ namespace constant
+ {
+ static const double e = 2.71828182845904523536028747135266249775724709369996;
+ static const double pi = 3.14159265358979323846264338327950288419716939937510;
+ static const double pi_2 = 1.57079632679489661923132169163975144209858469968755;
+ static const double pi_4 = 0.78539816339744830961566084581987572104929234984378;
+ static const double pi_180 = 0.01745329251994329576923690768488612713442871888542;
+ static const double _1_pi = 0.31830988618379067153776752674502872406891929148091;
+ static const double _2_pi = 0.63661977236758134307553505349005744813783858296183;
+ static const double _180_pi = 57.29577951308232087679815481410517033240547246656443;
+ static const double log2 = 0.69314718055994530941723212145817656807550013436026;
+ static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695;
+ }
+
+ namespace details
+ {
+ struct unknown_type_tag { unknown_type_tag() {} };
+ struct real_type_tag { real_type_tag () {} };
+ struct complex_type_tag { complex_type_tag() {} };
+ struct int_type_tag { int_type_tag () {} };
+
+ template <typename T>
+ struct number_type
+ {
+ typedef unknown_type_tag type;
+ number_type() {}
+ };
+
+ #define exprtk_register_real_type_tag(T) \
+ template<> struct number_type<T> \
+ { typedef real_type_tag type; number_type() {} }; \
+
+ #define exprtk_register_complex_type_tag(T) \
+ template<> struct number_type<std::complex<T> > \
+ { typedef complex_type_tag type; number_type() {} }; \
+
+ #define exprtk_register_int_type_tag(T) \
+ template<> struct number_type<T> \
+ { typedef int_type_tag type; number_type() {} }; \
+
+ exprtk_register_real_type_tag(double )
+ exprtk_register_real_type_tag(long double)
+ exprtk_register_real_type_tag(float )
+
+ exprtk_register_complex_type_tag(double )
+ exprtk_register_complex_type_tag(long double)
+ exprtk_register_complex_type_tag(float )
+
+ exprtk_register_int_type_tag(short )
+ exprtk_register_int_type_tag(int )
+ exprtk_register_int_type_tag(_int64_t )
+ exprtk_register_int_type_tag(unsigned short)
+ exprtk_register_int_type_tag(unsigned int )
+ exprtk_register_int_type_tag(_uint64_t )
+
+ #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 _int64_t to_int64_impl(const T v, real_type_tag)
+ {
+ return static_cast<_int64_t>(v);
+ }
+
+ template <typename T>
+ inline bool is_true_impl(const T v)
+ {
+ return std::not_equal_to<T>()(T(0),v);
+ }
+
+ template <typename T>
+ inline bool is_false_impl(const T v)
+ {
+ return std::equal_to<T>()(T(0),v);
+ }
+
+ template <typename T>
+ inline T abs_impl(const T v, real_type_tag)
+ {
+ return ((v < T(0)) ? -v : v);
+ }
+
+ template <typename T>
+ inline T min_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::min<T>(v0,v1);
+ }
+
+ template <typename T>
+ inline T max_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::max<T>(v0,v1);
+ }
+
+ template <typename T>
+ inline T equal_impl(const T v0, const T v1, real_type_tag)
+ {
+ const T epsilon = epsilon_type<T>::value();
+ return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0);
+ }
+
+ inline float equal_impl(const float v0, const float v1, real_type_tag)
+ {
+ const float epsilon = epsilon_type<float>::value();
+ return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f;
+ }
+
+ template <typename T>
+ inline T equal_impl(const T v0, const T v1, int_type_tag)
+ {
+ return (v0 == v1) ? 1 : 0;
+ }
+
+ template <typename T>
+ inline T expm1_impl(const T v, real_type_tag)
+ {
+ // return std::expm1<T>(v);
+ if (abs_impl(v,real_type_tag()) < T(0.00001))
+ return v + (T(0.5) * v * v);
+ else
+ return std::exp(v) - T(1);
+ }
+
+ template <typename T>
+ inline T expm1_impl(const T v, int_type_tag)
+ {
+ return T(std::exp<double>(v)) - T(1);
+ }
+
+ template <typename T>
+ inline T nequal_impl(const T v0, const T v1, real_type_tag)
+ {
+ typedef real_type_tag rtg;
+ const T epsilon = epsilon_type<T>::value();
+ return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0);
+ }
+
+ inline float nequal_impl(const float v0, const float v1, real_type_tag)
+ {
+ typedef real_type_tag rtg;
+ const float epsilon = epsilon_type<float>::value();
+ return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f;
+ }
+
+ template <typename T>
+ inline T nequal_impl(const T v0, const T v1, int_type_tag)
+ {
+ return (v0 != v1) ? 1 : 0;
+ }
+
+ template <typename T>
+ inline T modulus_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::fmod(v0,v1);
+ }
+
+ template <typename T>
+ inline T modulus_impl(const T v0, const T v1, int_type_tag)
+ {
+ return v0 % v1;
+ }
+
+ template <typename T>
+ inline T pow_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::pow(v0,v1);
+ }
+
+ template <typename T>
+ inline T pow_impl(const T v0, const T v1, int_type_tag)
+ {
+ return std::pow(static_cast<double>(v0),static_cast<double>(v1));
+ }
+
+ template <typename T>
+ inline T logn_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::log(v0) / std::log(v1);
+ }
+
+ template <typename T>
+ inline T logn_impl(const T v0, const T v1, int_type_tag)
+ {
+ return static_cast<T>(logn_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag()));
+ }
+
+ template <typename T>
+ inline T log1p_impl(const T v, real_type_tag)
+ {
+ if (v > T(-1))
+ {
+ if (abs_impl(v,real_type_tag()) > T(0.0001))
+ {
+ return std::log(T(1) + v);
+ }
+ else
+ return (T(-0.5) * v + T(1)) * v;
+ }
+ else
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ template <typename T>
+ inline T log1p_impl(const T v, int_type_tag)
+ {
+ if (v > T(-1))
+ {
+ return std::log(T(1) + v);
+ }
+ else
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ template <typename T>
+ inline T root_impl(const T v0, const T v1, real_type_tag)
+ {
+ if (v1 < T(0))
+ return std::numeric_limits<T>::quiet_NaN();
+
+ const std::size_t n = static_cast<std::size_t>(v1);
+
+ if ((v0 < T(0)) && (0 == (n % 2)))
+ return std::numeric_limits<T>::quiet_NaN();
+
+ return std::pow(v0, T(1) / n);
+ }
+
+ template <typename T>
+ inline T root_impl(const T v0, const T v1, int_type_tag)
+ {
+ return root_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag());
+ }
+
+ template <typename T>
+ inline T round_impl(const T v, real_type_tag)
+ {
+ return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5)));
+ }
+
+ template <typename T>
+ inline T roundn_impl(const T v0, const T v1, real_type_tag)
+ {
+ const int index = std::max<int>(0, std::min<int>(pow10_size - 1, (int)std::floor(v1)));
+ const T p10 = T(pow10[index]);
+
+ if (v0 < T(0))
+ return T(std::ceil ((v0 * p10) - T(0.5)) / p10);
+ else
+ return T(std::floor((v0 * p10) + T(0.5)) / p10);
+ }
+
+ template <typename T>
+ inline T roundn_impl(const T v0, const T, int_type_tag)
+ {
+ return v0;
+ }
+
+ template <typename T>
+ inline T hypot_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::sqrt((v0 * v0) + (v1 * v1));
+ }
+
+ template <typename T>
+ inline T hypot_impl(const T v0, const T v1, int_type_tag)
+ {
+ return static_cast<T>(std::sqrt(static_cast<double>((v0 * v0) + (v1 * v1))));
+ }
+
+ template <typename T>
+ inline T atan2_impl(const T v0, const T v1, real_type_tag)
+ {
+ return std::atan2(v0,v1);
+ }
+
+ template <typename T>
+ inline T atan2_impl(const T, const T, int_type_tag)
+ {
+ return 0;
+ }
+
+ template <typename T>
+ inline T shr_impl(const T v0, const T v1, real_type_tag)
+ {
+ return v0 * (T(1) / std::pow(T(2),static_cast<T>(static_cast<int>(v1))));
+ }
+
+ template <typename T>
+ inline T shr_impl(const T v0, const T v1, int_type_tag)
+ {
+ return v0 >> v1;
+ }
+
+ template <typename T>
+ inline T shl_impl(const T v0, const T v1, real_type_tag)
+ {
+ return v0 * std::pow(T(2),static_cast<T>(static_cast<int>(v1)));
+ }
+
+ template <typename T>
+ inline T shl_impl(const T v0, const T v1, int_type_tag)
+ {
+ return v0 << v1;
+ }
+
+ template <typename T>
+ inline T sgn_impl(const T v, real_type_tag)
+ {
+ if (v > T(0)) return T(+1);
+ else if (v < T(0)) return T(-1);
+ else return T( 0);
+ }
+
+ template <typename T>
+ inline T sgn_impl(const T v, int_type_tag)
+ {
+ if (v > T(0)) return T(+1);
+ else if (v < T(0)) return T(-1);
+ else return T( 0);
+ }
+
+ template <typename T>
+ inline T and_impl(const T v0, const T v1, real_type_tag)
+ {
+ return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0);
+ }
+
+ template <typename T>
+ inline T and_impl(const T v0, const T v1, int_type_tag)
+ {
+ return v0 && v1;
+ }
+
+ template <typename T>
+ inline T nand_impl(const T v0, const T v1, real_type_tag)
+ {
+ return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0);
+ }
+
+ template <typename T>
+ inline T nand_impl(const T v0, const T v1, int_type_tag)
+ {
+ return !(v0 && v1);
+ }
+
+ template <typename T>
+ inline T or_impl(const T v0, const T v1, real_type_tag)
+ {
+ return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0);
+ }
+
+ template <typename T>
+ inline T or_impl(const T v0, const T v1, int_type_tag)
+ {
+ return (v0 || v1);
+ }
+
+ template <typename T>
+ inline T nor_impl(const T v0, const T v1, real_type_tag)
+ {
+ return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0);
+ }
+
+ template <typename T>
+ inline T nor_impl(const T v0, const T v1, int_type_tag)
+ {
+ return !(v0 || v1);
+ }
+
+ template <typename T>
+ inline T xor_impl(const T v0, const T v1, real_type_tag)
+ {
+ return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0);
+ }
+
+ template <typename T>
+ inline T xor_impl(const T v0, const T v1, int_type_tag)
+ {
+ return v0 ^ v1;
+ }
+
+ template <typename T>
+ inline T xnor_impl(const T v0, const T v1, real_type_tag)
+ {
+ const bool v0_true = is_true_impl(v0);
+ const bool v1_true = is_true_impl(v1);
+
+ if ((v0_true && v1_true) || (!v0_true && !v1_true))
+ return T(1);
+ else
+ return T(0);
+ }
+
+ template <typename T>
+ inline T xnor_impl(const T v0, const T v1, int_type_tag)
+ {
+ const bool v0_true = is_true_impl(v0);
+ const bool v1_true = is_true_impl(v1);
+
+ if ((v0_true && v1_true) || (!v0_true && !v1_true))
+ return T(1);
+ else
+ return T(0);
+ }
+
+ #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER)
+ #define exprtk_define_erf(TT,impl) \
+ inline TT erf_impl(TT v) { return impl(v); } \
+
+ exprtk_define_erf( float,::erff)
+ exprtk_define_erf( double,::erf )
+ exprtk_define_erf(long double,::erfl)
+ #undef exprtk_define_erf
+ #endif
+
+ template <typename T>
+ inline T erf_impl(T v, real_type_tag)
+ {
+ #if defined(_MSC_VER) && (_MSC_VER < 1900)
+ // Credits: Abramowitz & Stegun Equations 7.1.25-28
+ static const T c[] = {
+ T( 1.26551223), T(1.00002368),
+ T( 0.37409196), T(0.09678418),
+ T(-0.18628806), T(0.27886807),
+ T(-1.13520398), T(1.48851587),
+ T(-0.82215223), T(0.17087277)
+ };
+
+ const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag()));
+
+ T result = T(1) - t * std::exp((-v * v) -
+ c[0] + t * (c[1] + t *
+ (c[2] + t * (c[3] + t *
+ (c[4] + t * (c[5] + t *
+ (c[6] + t * (c[7] + t *
+ (c[8] + t * (c[9]))))))))));
+
+ return (v >= T(0)) ? result : -result;
+ #else
+ return erf_impl(v);
+ #endif
+ }
+
+ template <typename T>
+ inline T erf_impl(T v, int_type_tag)
+ {
+ return erf_impl(static_cast<double>(v),real_type_tag());
+ }
+
+ #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER)
+ #define exprtk_define_erfc(TT,impl) \
+ inline TT erfc_impl(TT v) { return impl(v); } \
+
+ exprtk_define_erfc( float,::erfcf)
+ exprtk_define_erfc( double,::erfc )
+ exprtk_define_erfc(long double,::erfcl)
+ #undef exprtk_define_erfc
+ #endif
+
+ template <typename T>
+ inline T erfc_impl(T v, real_type_tag)
+ {
+ #if defined(_MSC_VER) && (_MSC_VER < 1900)
+ return T(1) - erf_impl(v,real_type_tag());
+ #else
+ return erfc_impl(v);
+ #endif
+ }
+
+ template <typename T>
+ inline T erfc_impl(T v, int_type_tag)
+ {
+ return erfc_impl(static_cast<double>(v),real_type_tag());
+ }
+
+ template <typename T>
+ inline T ncdf_impl(T v, real_type_tag)
+ {
+ T cnd = T(0.5) * (T(1) + erf_impl(
+ abs_impl(v,real_type_tag()) /
+ T(numeric::constant::sqrt2),real_type_tag()));
+ return (v < T(0)) ? (T(1) - cnd) : cnd;
+ }
+
+ template <typename T>
+ inline T ncdf_impl(T v, int_type_tag)
+ {
+ return ncdf_impl(static_cast<double>(v),real_type_tag());
+ }
+
+ template <typename T>
+ inline T sinc_impl(T v, real_type_tag)
+ {
+ if (std::abs(v) >= std::numeric_limits<T>::epsilon())
+ return(std::sin(v) / v);
+ else
+ return T(1);
+ }
+
+ template <typename T>
+ inline T sinc_impl(T v, int_type_tag)
+ {
+ return sinc_impl(static_cast<double>(v),real_type_tag());
+ }
+
+ template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); }
+ template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); }
+ template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); }
+ template <typename T> inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); }
+ template <typename T> inline T atan_impl(const T v, real_type_tag) { return std::atan (v); }
+ template <typename T> inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); }
+ template <typename T> inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); }
+ template <typename T> inline T cos_impl(const T v, real_type_tag) { return std::cos (v); }
+ template <typename T> inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); }
+ template <typename T> inline T exp_impl(const T v, real_type_tag) { return std::exp (v); }
+ template <typename T> inline T floor_impl(const T v, real_type_tag) { return std::floor(v); }
+ template <typename T> inline T log_impl(const T v, real_type_tag) { return std::log (v); }
+ template <typename T> inline T log10_impl(const T v, real_type_tag) { return std::log10(v); }
+ template <typename T> inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); }
+ template <typename T> inline T neg_impl(const T v, real_type_tag) { return -v; }
+ template <typename T> inline T pos_impl(const T v, real_type_tag) { return +v; }
+ template <typename T> inline T sin_impl(const T v, real_type_tag) { return std::sin (v); }
+ template <typename T> inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); }
+ template <typename T> inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); }
+ template <typename T> inline T tan_impl(const T v, real_type_tag) { return std::tan (v); }
+ template <typename T> inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); }
+ template <typename T> inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); }
+ template <typename T> inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); }
+ template <typename T> inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); }
+ template <typename T> inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); }
+ template <typename T> inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); }
+ template <typename T> inline T d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); }
+ template <typename T> inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); }
+ template <typename T> inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to<T>()(T(0),v) ? T(0) : T(1)); }
+ template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); }
+ template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); }
+
+ template <typename T> inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); }
+ template <typename T> inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); }
+
+ 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)
+ {
+ const typename details::number_type<T>::type num_type;
+ return to_int32_impl(v, num_type);
+ }
+
+ template <typename T>
+ inline _int64_t to_int64(const T v)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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)
+ {
+ const 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) \
+ { \
+ const 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;
+
+ const bool negative = ('-' == (*itr));
+
+ if (negative || ('+' == (*itr)))
+ {
+ if (end == ++itr)
+ return false;
+ }
+
+ static const uchar_t zero = static_cast<uchar_t>('0');
+
+ while ((end != itr) && (zero == (*itr))) ++itr;
+
+ bool return_result = true;
+ unsigned int digit = 0;
+ const std::size_t length = static_cast<std::size_t>(std::distance(itr,end));
+
+ if (length <= 4)
+ {
+ exprtk_disable_fallthrough_begin
+ 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++ - zero)) < 10) \
+ result = result * T(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 - zero))>= 10) { digit = 0; return_result = false; }
+
+ #undef exprtk_process_digit
+ }
+ exprtk_disable_fallthrough_end
+ }
+ else
+ return_result = false;
+
+ if (length && return_result)
+ {
+ result = result * 10 + static_cast<T>(digit);
+ ++itr;
+ }
+
+ result = negative ? -result : result;
+ return return_result;
+ }
+
+ template <typename Iterator, typename T>
+ static inline bool parse_nan(Iterator& itr, const Iterator end, T& t)
+ {
+ typedef typename std::iterator_traits<Iterator>::value_type type;
+
+ static const std::size_t nan_length = 3;
+
+ if (std::distance(itr,end) != static_cast<int>(nan_length))
+ return false;
+
+ if (static_cast<type>('n') == (*itr))
+ {
+ if (
+ (static_cast<type>('a') != *(itr + 1)) ||
+ (static_cast<type>('n') != *(itr + 2))
+ )
+ {
+ return false;
+ }
+ }
+ else if (
+ (static_cast<type>('A') != *(itr + 1)) ||
+ (static_cast<type>('N') != *(itr + 2))
+ )
+ {
+ return false;
+ }
+
+ t = std::numeric_limits<T>::quiet_NaN();
+
+ return true;
+ }
+
+ template <typename Iterator, typename T>
+ static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative)
+ {
+ static const char_t inf_uc[] = "INFINITY";
+ static const char_t inf_lc[] = "infinity";
+ static const std::size_t inf_length = 8;
+
+ const std::size_t length = static_cast<std::size_t>(std::distance(itr,end));
+
+ if ((3 != length) && (inf_length != length))
+ return false;
+
+ char_cptr 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);
+
+ const bool negative = ('-' == (*itr));
+
+ if (negative || '+' == (*itr))
+ {
+ if (end == ++itr)
+ return false;
+ }
+
+ bool instate = false;
+
+ static const char_t zero = static_cast<uchar_t>('0');
+
+ #define parse_digit_1(d) \
+ if ((digit = (*itr - zero)) < 10) \
+ { d = d * T(10) + digit; } \
+ else \
+ { break; } \
+ if (end == ++itr) break; \
+
+ #define parse_digit_2(d) \
+ if ((digit = (*itr - zero)) < 10) \
+ { d = d * T(10) + digit; } \
+ else { break; } \
+ ++itr; \
+
+ if ('.' != (*itr))
+ {
+ const Iterator curr = itr;
+
+ while ((end != itr) && (zero == (*itr))) ++itr;
+
+ unsigned int digit;
+
+ while (end != itr)
+ {
+ // Note: For 'physical' superscalar architectures it
+ // is advised that the following loop be: 4xPD1 and 1xPD2
+ #ifdef exprtk_enable_superscalar
+ parse_digit_1(d)
+ parse_digit_1(d)
+ #endif
+ parse_digit_1(d)
+ parse_digit_1(d)
+ parse_digit_2(d)
+ }
+
+ if (curr != itr) instate = true;
+ }
+
+ int exponent = 0;
+
+ if (end != itr)
+ {
+ if ('.' == (*itr))
+ {
+ const Iterator curr = ++itr;
+ unsigned int digit;
+ T tmp_d = T(0);
+
+ while (end != itr)
+ {
+ #ifdef exprtk_enable_superscalar
+ parse_digit_1(tmp_d)
+ parse_digit_1(tmp_d)
+ parse_digit_1(tmp_d)
+ #endif
+ parse_digit_1(tmp_d)
+ parse_digit_1(tmp_d)
+ parse_digit_2(tmp_d)
+ }
+
+ if (curr != itr)
+ {
+ instate = true;
+ d += compute_pow10(tmp_d,static_cast<int>(-std::distance(curr,itr)));
+ }
+
+ #undef parse_digit_1
+ #undef parse_digit_2
+ }
+
+ if (end != itr)
+ {
+ typename std::iterator_traits<Iterator>::value_type c = (*itr);
+
+ if (('e' == c) || ('E' == c))
+ {
+ int exp = 0;
+
+ if (!details::string_to_type_converter_impl_ref(++itr, end, exp))
+ {
+ if (end == itr)
+ return false;
+ else
+ c = (*itr);
+ }
+
+ exponent += exp;
+ }
+
+ if (end != itr)
+ {
+ if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c))
+ ++itr;
+ else if ('#' == c)
+ {
+ if (end == ++itr)
+ return false;
+ else if (('I' <= (*itr)) && ((*itr) <= 'n'))
+ {
+ if (('i' == (*itr)) || ('I' == (*itr)))
+ {
+ return parse_inf(itr, end, t, negative);
+ }
+ else if (('n' == (*itr)) || ('N' == (*itr)))
+ {
+ return parse_nan(itr, end, t);
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+ else if (('I' <= (*itr)) && ((*itr) <= 'n'))
+ {
+ if (('i' == (*itr)) || ('I' == (*itr)))
+ {
+ return parse_inf(itr, end, t, negative);
+ }
+ else if (('n' == (*itr)) || ('N' == (*itr)))
+ {
+ return parse_nan(itr, end, t);
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+ }
+ }
+
+ if ((end != itr) || (!instate))
+ return false;
+ else if (exponent)
+ d = compute_pow10(d,exponent);
+
+ t = static_cast<T>((negative) ? -d : d);
+ return true;
+ }
+
+ template <typename T>
+ inline bool string_to_real(const std::string& s, T& t)
+ {
+ const typename numeric::details::number_type<T>::type num_type;
+
+ char_cptr begin = s.data();
+ char_cptr end = s.data() + s.size();
+
+ return string_to_real(begin, end, t, num_type);
+ }
+
+ template <typename T>
+ struct functor_t
+ {
+ /*
+ Note: The following definitions for Type, may require tweaking
+ based on the compiler and target architecture. The benchmark
+ should provide enough information to make the right choice.
+ */
+ //typedef T Type;
+ //typedef const T Type;
+ typedef const T& Type;
+ typedef T& RefType;
+ typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3);
+ typedef T (*tfunc_t)(Type t0, Type t1, Type t2);
+ typedef T (*bfunc_t)(Type t0, Type t1);
+ typedef T (*ufunc_t)(Type t0);
+ };
+
+ } // namespace details
+
+ namespace lexer
+ {
+ struct token
+ {
+ enum token_type
+ {
+ e_none = 0, e_error = 1, e_err_symbol = 2,
+ e_err_number = 3, e_err_string = 4, e_err_sfunc = 5,
+ e_eof = 6, e_number = 7, e_symbol = 8,
+ e_string = 9, e_assign = 10, e_addass = 11,
+ e_subass = 12, e_mulass = 13, e_divass = 14,
+ e_modass = 15, e_shr = 16, e_shl = 17,
+ e_lte = 18, e_ne = 19, e_gte = 20,
+ e_swap = 21, e_lt = '<', e_gt = '>',
+ e_eq = '=', e_rbracket = ')', e_lbracket = '(',
+ e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}',
+ e_lcrlbracket = '{', e_comma = ',', e_add = '+',
+ e_sub = '-', e_div = '/', e_mul = '*',
+ e_mod = '%', e_pow = '^', e_colon = ':',
+ e_ternary = '?'
+ };
+
+ token()
+ : type(e_none),
+ value(""),
+ position(std::numeric_limits<std::size_t>::max())
+ {}
+
+ void clear()
+ {
+ type = e_none;
+ value = "";
+ position = std::numeric_limits<std::size_t>::max();
+ }
+
+ template <typename Iterator>
+ inline token& set_operator(const token_type tt,
+ const Iterator begin, const Iterator end,
+ const Iterator base_begin = Iterator(0))
+ {
+ type = tt;
+ value.assign(begin,end);
+ if (base_begin)
+ position = static_cast<std::size_t>(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 = static_cast<std::size_t>(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 = static_cast<std::size_t>(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 = static_cast<std::size_t>(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 = static_cast<std::size_t>(std::distance(base_begin,begin));
+
+ return (*this);
+ }
+
+ static inline std::string to_str(token_type t)
+ {
+ switch (t)
+ {
+ case e_none : return "NONE";
+ case e_error : return "ERROR";
+ case e_err_symbol : return "ERROR_SYMBOL";
+ case e_err_number : return "ERROR_NUMBER";
+ case e_err_string : return "ERROR_STRING";
+ case e_eof : return "EOF";
+ case e_number : return "NUMBER";
+ case e_symbol : return "SYMBOL";
+ case e_string : return "STRING";
+ case e_assign : return ":=";
+ case e_addass : return "+=";
+ case e_subass : return "-=";
+ case e_mulass : return "*=";
+ case e_divass : return "/=";
+ case e_modass : return "%=";
+ case e_shr : return ">>";
+ case e_shl : return "<<";
+ case e_lte : return "<=";
+ case e_ne : return "!=";
+ case e_gte : return ">=";
+ case e_lt : return "<";
+ case e_gt : return ">";
+ case e_eq : return "=";
+ case e_rbracket : return ")";
+ case e_lbracket : return "(";
+ case e_rsqrbracket : return "]";
+ case e_lsqrbracket : return "[";
+ case e_rcrlbracket : return "}";
+ case e_lcrlbracket : return "{";
+ case e_comma : return ",";
+ case e_add : return "+";
+ case e_sub : return "-";
+ case e_div : return "/";
+ case e_mul : return "*";
+ case e_mod : return "%";
+ case e_pow : return "^";
+ case e_colon : return ":";
+ case e_ternary : return "?";
+ case e_swap : return "<=>";
+ default : return "UNKNOWN";
+ }
+ }
+
+ inline bool is_error() const
+ {
+ return (
+ (e_error == type) ||
+ (e_err_symbol == type) ||
+ (e_err_number == type) ||
+ (e_err_string == type) ||
+ (e_err_sfunc == type)
+ );
+ }
+
+ token_type type;
+ std::string value;
+ std::size_t position;
+ };
+
+ class generator
+ {
+ public:
+
+ typedef token token_t;
+ typedef std::vector<token_t> token_list_t;
+ typedef std::vector<token_t>::iterator token_list_itr_t;
+ typedef details::char_t char_t;
+
+ generator()
+ : base_itr_(0),
+ s_itr_ (0),
+ s_end_ (0)
+ {
+ clear();
+ }
+
+ inline void clear()
+ {
+ base_itr_ = 0;
+ s_itr_ = 0;
+ s_end_ = 0;
+ token_list_.clear();
+ token_itr_ = token_list_.end();
+ store_token_itr_ = token_list_.end();
+ }
+
+ inline bool process(const std::string& str)
+ {
+ base_itr_ = str.data();
+ s_itr_ = str.data();
+ s_end_ = str.data() + str.size();
+
+ eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_);
+ token_list_.clear();
+
+ while (!is_end(s_itr_))
+ {
+ scan_token();
+
+ if (!token_list_.empty() && token_list_.back().is_error())
+ return false;
+ }
+
+ return true;
+ }
+
+ inline bool empty() const
+ {
+ return token_list_.empty();
+ }
+
+ inline std::size_t size() const
+ {
+ return token_list_.size();
+ }
+
+ inline void begin()
+ {
+ token_itr_ = token_list_.begin();
+ store_token_itr_ = token_list_.begin();
+ }
+
+ inline void store()
+ {
+ store_token_itr_ = token_itr_;
+ }
+
+ inline void restore()
+ {
+ token_itr_ = store_token_itr_;
+ }
+
+ inline token_t& next_token()
+ {
+ if (token_list_.end() != token_itr_)
+ {
+ return *token_itr_++;
+ }
+ else
+ return eof_token_;
+ }
+
+ inline token_t& peek_next_token()
+ {
+ if (token_list_.end() != token_itr_)
+ {
+ return *token_itr_;
+ }
+ else
+ return eof_token_;
+ }
+
+ inline token_t& operator[](const std::size_t& index)
+ {
+ if (index < token_list_.size())
+ return token_list_[index];
+ else
+ return eof_token_;
+ }
+
+ inline token_t operator[](const std::size_t& index) const
+ {
+ if (index < token_list_.size())
+ return token_list_[index];
+ else
+ return eof_token_;
+ }
+
+ inline bool finished() const
+ {
+ return (token_list_.end() == token_itr_);
+ }
+
+ inline void insert_front(token_t::token_type tk_type)
+ {
+ if (
+ !token_list_.empty() &&
+ (token_list_.end() != token_itr_)
+ )
+ {
+ token_t t = *token_itr_;
+
+ t.type = tk_type;
+ token_itr_ = token_list_.insert(token_itr_,t);
+ }
+ }
+
+ inline std::string substr(const std::size_t& begin, const std::size_t& end)
+ {
+ const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
+ const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_;
+
+ return std::string(begin_itr,end_itr);
+ }
+
+ inline std::string remaining() const
+ {
+ if (finished())
+ return "";
+ else if (token_list_.begin() != token_itr_)
+ return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_);
+ else
+ return std::string(base_itr_ + token_itr_->position, s_end_);
+ }
+
+ private:
+
+ inline bool is_end(details::char_cptr itr)
+ {
+ return (s_end_ == itr);
+ }
+
+ inline bool is_comment_start(details::char_cptr itr)
+ {
+ #ifndef exprtk_disable_comments
+ const char_t c0 = *(itr + 0);
+ const char_t c1 = *(itr + 1);
+
+ if ('#' == c0)
+ return true;
+ else if (!is_end(itr + 1))
+ {
+ if (('/' == c0) && ('/' == c1)) return true;
+ if (('/' == c0) && ('*' == c1)) return true;
+ }
+ #endif
+ return false;
+ }
+
+ inline void skip_whitespace()
+ {
+ while (!is_end(s_itr_) && details::is_whitespace(*s_itr_))
+ {
+ ++s_itr_;
+ }
+ }
+
+ inline void skip_comments()
+ {
+ #ifndef exprtk_disable_comments
+ // The following comment styles are supported:
+ // 1. // .... \n
+ // 2. # .... \n
+ // 3. /* .... */
+ struct test
+ {
+ static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr)
+ {
+ mode = 0;
+ if ('#' == c0) { mode = 1; incr = 1; }
+ else if ('/' == c0)
+ {
+ if ('/' == c1) { mode = 1; incr = 2; }
+ else if ('*' == c1) { mode = 2; incr = 2; }
+ }
+ return (0 != mode);
+ }
+
+ static inline bool comment_end(const char_t c0, const char_t c1, int& mode)
+ {
+ if (
+ ((1 == mode) && ('\n' == c0)) ||
+ ((2 == mode) && ( '*' == c0) && ('/' == c1))
+ )
+ {
+ mode = 0;
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ int mode = 0;
+ int increment = 0;
+
+ if (is_end(s_itr_))
+ return;
+ else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment))
+ return;
+
+ details::char_cptr cmt_start = s_itr_;
+
+ s_itr_ += increment;
+
+ while (!is_end(s_itr_))
+ {
+ if ((1 == mode) && test::comment_end(*s_itr_, 0, mode))
+ {
+ ++s_itr_;
+ return;
+ }
+
+ if ((2 == mode))
+ {
+ if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode))
+ {
+ s_itr_ += 2;
+ return;
+ }
+ }
+
+ ++s_itr_;
+ }
+
+ if (2 == mode)
+ {
+ token_t t;
+ t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_);
+ token_list_.push_back(t);
+ }
+ #endif
+ }
+
+ inline void scan_token()
+ {
+ if (details::is_whitespace(*s_itr_))
+ {
+ skip_whitespace();
+ return;
+ }
+ else if (is_comment_start(s_itr_))
+ {
+ skip_comments();
+ return;
+ }
+ else if (details::is_operator_char(*s_itr_))
+ {
+ scan_operator();
+ return;
+ }
+ else if (details::is_letter(*s_itr_))
+ {
+ scan_symbol();
+ return;
+ }
+ else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_)))
+ {
+ scan_number();
+ return;
+ }
+ else if ('$' == (*s_itr_))
+ {
+ scan_special_function();
+ return;
+ }
+ #ifndef exprtk_disable_string_capabilities
+ else if ('\'' == (*s_itr_))
+ {
+ scan_string();
+ return;
+ }
+ #endif
+ else if ('~' == (*s_itr_))
+ {
+ token_t t;
+ t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
+ token_list_.push_back(t);
+ ++s_itr_;
+ return;
+ }
+ else
+ {
+ token_t t;
+ t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_);
+ token_list_.push_back(t);
+ ++s_itr_;
+ }
+ }
+
+ inline void scan_operator()
+ {
+ token_t t;
+
+ const char_t c0 = s_itr_[0];
+
+ if (!is_end(s_itr_ + 1))
+ {
+ const char_t c1 = s_itr_[1];
+
+ if (!is_end(s_itr_ + 2))
+ {
+ const char_t c2 = s_itr_[2];
+
+ if ((c0 == '<') && (c1 == '=') && (c2 == '>'))
+ {
+ t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_);
+ token_list_.push_back(t);
+ s_itr_ += 3;
+ return;
+ }
+ }
+
+ token_t::token_type ttype = token_t::e_none;
+
+ if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte;
+ else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte;
+ else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne;
+ else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne;
+ else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq;
+ else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign;
+ else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl;
+ else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr;
+ else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass;
+ else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass;
+ else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass;
+ else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass;
+ else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass;
+
+ if (token_t::e_none != ttype)
+ {
+ t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_);
+ token_list_.push_back(t);
+ s_itr_ += 2;
+ return;
+ }
+ }
+
+ if ('<' == c0)
+ t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_);
+ else if ('>' == c0)
+ t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_);
+ else if (';' == c0)
+ t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_);
+ else if ('&' == c0)
+ t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
+ else if ('|' == c0)
+ t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
+ else
+ t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_);
+
+ token_list_.push_back(t);
+ ++s_itr_;
+ }
+
+ inline void scan_symbol()
+ {
+ details::char_cptr initial_itr = s_itr_;
+
+ while (!is_end(s_itr_))
+ {
+ if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_)))
+ {
+ if ('.' != (*s_itr_))
+ break;
+ /*
+ Permit symbols that contain a 'dot'
+ Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123
+ Disallowed: .abc, abc.<white-space>, abc.<eof>, abc.<operator +,-,*,/...>
+ */
+ if (
+ (s_itr_ != initial_itr) &&
+ !is_end(s_itr_ + 1) &&
+ !details::is_letter_or_digit(*(s_itr_ + 1)) &&
+ ('_' != (*(s_itr_ + 1)))
+ )
+ break;
+ }
+
+ ++s_itr_;
+ }
+
+ token_t t;
+ t.set_symbol(initial_itr,s_itr_,base_itr_);
+ token_list_.push_back(t);
+ }
+
+ inline void scan_number()
+ {
+ /*
+ Attempt to match a valid numeric value in one of the following formats:
+ (01) 123456
+ (02) 123456.
+ (03) 123.456
+ (04) 123.456e3
+ (05) 123.456E3
+ (06) 123.456e+3
+ (07) 123.456E+3
+ (08) 123.456e-3
+ (09) 123.456E-3
+ (00) .1234
+ (11) .1234e3
+ (12) .1234E+3
+ (13) .1234e+3
+ (14) .1234E-3
+ (15) .1234e-3
+ */
+
+ details::char_cptr initial_itr = s_itr_;
+ bool dot_found = false;
+ bool e_found = false;
+ bool post_e_sign_found = false;
+ bool post_e_digit_found = false;
+ token_t t;
+
+ while (!is_end(s_itr_))
+ {
+ if ('.' == (*s_itr_))
+ {
+ if (dot_found)
+ {
+ t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+ return;
+ }
+
+ dot_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if ('e' == std::tolower(*s_itr_))
+ {
+ const char_t& c = *(s_itr_ + 1);
+
+ if (is_end(s_itr_ + 1))
+ {
+ t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+ else if (
+ ('+' != c) &&
+ ('-' != c) &&
+ !details::is_digit(c)
+ )
+ {
+ t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ e_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found)
+ {
+ if (post_e_sign_found)
+ {
+ t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ post_e_sign_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (e_found && details::is_digit(*s_itr_))
+ {
+ post_e_digit_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_))
+ break;
+ else
+ ++s_itr_;
+ }
+
+ t.set_numeric(initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ inline void scan_special_function()
+ {
+ details::char_cptr 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()
+ {
+ details::char_cptr initial_itr = s_itr_ + 1;
+ token_t t;
+
+ if (std::distance(s_itr_,s_end_) < 2)
+ {
+ t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_);
+ token_list_.push_back(t);
+ return;
+ }
+
+ ++s_itr_;
+
+ bool escaped_found = false;
+ bool escaped = false;
+
+ while (!is_end(s_itr_))
+ {
+ if (!escaped && ('\\' == *s_itr_))
+ {
+ escaped_found = true;
+ escaped = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (!escaped)
+ {
+ if ('\'' == *s_itr_)
+ break;
+ }
+ else if (escaped)
+ {
+ if (!is_end(s_itr_) && ('0' == *(s_itr_)))
+ {
+ /*
+ Note: The following 'awkward' conditional is
+ due to various broken msvc compilers.
+ */
+ #if defined(_MSC_VER) && (_MSC_VER == 1600)
+ const bool within_range = !is_end(s_itr_ + 2) &&
+ !is_end(s_itr_ + 3) ;
+ #else
+ const bool within_range = !is_end(s_itr_ + 1) &&
+ !is_end(s_itr_ + 2) &&
+ !is_end(s_itr_ + 3) ;
+ #endif
+
+ const bool x_seperator = ('x' == *(s_itr_ + 1)) ||
+ ('X' == *(s_itr_ + 1)) ;
+
+ const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) &&
+ details::is_hex_digit(*(s_itr_ + 3)) ;
+
+ if (!within_range || !x_seperator || !both_digits)
+ {
+ t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+ else
+ s_itr_ += 3;
+ }
+
+ escaped = false;
+ }
+
+ ++s_itr_;
+ }
+
+ if (is_end(s_itr_))
+ {
+ t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ if (!escaped_found)
+ t.set_string(initial_itr, s_itr_, base_itr_);
+ else
+ {
+ std::string parsed_string(initial_itr,s_itr_);
+
+ details::cleanup_escapes(parsed_string);
+
+ t.set_string(
+ parsed_string,
+ static_cast<std::size_t>(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_;
+ details::char_cptr base_itr_;
+ details::char_cptr s_itr_;
+ details::char_cptr 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:
+
+ const 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;
+ }
+
+ typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
+
+ if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1)))
+ {
+ g.token_list_.insert(
+ g.token_list_.begin() + static_cast<diff_t>(i + static_cast<std::size_t>(insert_index)), t);
+
+ changes++;
+ }
+ }
+
+ return changes;
+ }
+
+ #define token_inserter_empty_body \
+ { \
+ return -1; \
+ } \
+
+ inline virtual int insert(const token&, token&)
+ token_inserter_empty_body
+
+ inline virtual int insert(const token&, const token&, token&)
+ token_inserter_empty_body
+
+ inline virtual int insert(const token&, const token&, const token&, token&)
+ token_inserter_empty_body
+
+ inline virtual int insert(const token&, const token&, const token&, const token&, token&)
+ token_inserter_empty_body
+
+ inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&)
+ token_inserter_empty_body
+
+ #undef token_inserter_empty_body
+
+ private:
+
+ const std::size_t stride_;
+ };
+
+ class token_joiner : public helper_interface
+ {
+ public:
+
+ explicit 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)
+ {
+ typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
+
+ if (g.token_list_.size() < 2)
+ return 0;
+
+ std::size_t changes = 0;
+
+ for (int i = 0; i < static_cast<int>(g.token_list_.size() - 1); ++i)
+ {
+ token t;
+
+ while (join(g[i], g[i + 1], t))
+ {
+ g.token_list_[i] = t;
+
+ g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1));
+
+ ++changes;
+
+ if (static_cast<std::size_t>(i + 1) >= g.token_list_.size())
+ break;
+ }
+ }
+
+ return changes;
+ }
+
+ inline std::size_t process_stride_3(generator& g)
+ {
+ typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
+
+ if (g.token_list_.size() < 3)
+ return 0;
+
+ std::size_t changes = 0;
+
+ for (int i = 0; i < static_cast<int>(g.token_list_.size() - 2); ++i)
+ {
+ token t;
+
+ while (join(g[i], g[i + 1], g[i + 2], t))
+ {
+ g.token_list_[i] = t;
+
+ g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1),
+ g.token_list_.begin() + static_cast<diff_t>(i + 3));
+ ++changes;
+
+ if (static_cast<std::size_t>(i + 2) >= g.token_list_.size())
+ break;
+ }
+ }
+
+ return changes;
+ }
+
+ const std::size_t stride_;
+ };
+
+ namespace helper
+ {
+
+ inline void dump(lexer::generator& generator)
+ {
+ for (std::size_t i = 0; i < generator.size(); ++i)
+ {
+ lexer::token t = generator[i];
+ printf("Token[%02d] @ %03d %6s --> '%s'\n",
+ static_cast<int>(i),
+ static_cast<int>(t.position),
+ t.to_str(t.type).c_str(),
+ t.value.c_str());
+ }
+ }
+
+ class commutative_inserter : public lexer::token_inserter
+ {
+ public:
+
+ using lexer::token_inserter::insert;
+
+ commutative_inserter()
+ : lexer::token_inserter(2)
+ {}
+
+ inline void ignore_symbol(const std::string& symbol)
+ {
+ ignore_set_.insert(symbol);
+ }
+
+ inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token)
+ {
+ bool match = false;
+ new_token.type = lexer::token::e_mul;
+ new_token.value = "*";
+ new_token.position = t1.position;
+
+ if (t0.type == lexer::token::e_symbol)
+ {
+ if (ignore_set_.end() != ignore_set_.find(t0.value))
+ {
+ return -1;
+ }
+ else if (!t0.value.empty() && ('$' == t0.value[0]))
+ {
+ return -1;
+ }
+ }
+
+ if (t1.type == lexer::token::e_symbol)
+ {
+ if (ignore_set_.end() != ignore_set_.find(t1.value))
+ {
+ return -1;
+ }
+ }
+ if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true;
+ else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true;
+ else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true;
+ else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true;
+ else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true;
+ else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true;
+ else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true;
+ else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true;
+ else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true;
+ else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true;
+ else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true;
+ else if ((t0.type == lexer::token::e_symbol ) && (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:
+
+ explicit operator_joiner(const std::size_t& stride)
+ : token_joiner(stride)
+ {}
+
+ inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t)
+ {
+ // ': =' --> ':='
+ if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_assign;
+ t.value = ":=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '+ =' --> '+='
+ else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_addass;
+ t.value = "+=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '- =' --> '-='
+ else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_subass;
+ t.value = "-=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '* =' --> '*='
+ else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_mulass;
+ t.value = "*=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '/ =' --> '/='
+ else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_divass;
+ t.value = "/=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '% =' --> '%='
+ else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_modass;
+ t.value = "%=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '> =' --> '>='
+ else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_gte;
+ t.value = ">=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '< =' --> '<='
+ else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_lte;
+ t.value = "<=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '= =' --> '=='
+ else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_eq;
+ t.value = "==";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '! =' --> '!='
+ else if ((static_cast<char>(t0.type) == '!') && (t1.type == lexer::token::e_eq))
+ {
+ t.type = lexer::token::e_ne;
+ t.value = "!=";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '< >' --> '<>'
+ else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt))
+ {
+ t.type = lexer::token::e_ne;
+ t.value = "<>";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '<= >' --> '<=>'
+ else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt))
+ {
+ t.type = lexer::token::e_swap;
+ t.value = "<=>";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '+ -' --> '-'
+ else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub))
+ {
+ t.type = lexer::token::e_sub;
+ t.value = "-";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '- +' --> '-'
+ else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add))
+ {
+ t.type = lexer::token::e_sub;
+ t.value = "-";
+ t.position = t0.position;
+
+ return true;
+ }
+ // '- -' --> '+'
+ else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub))
+ {
+ /*
+ Note: May need to reconsider this when wanting to implement
+ pre/postfix decrement operator
+ */
+ t.type = lexer::token::e_add;
+ t.value = "+";
+ t.position = t0.position;
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t)
+ {
+ // '[ * ]' --> '[*]'
+ if (
+ (t0.type == lexer::token::e_lsqrbracket) &&
+ (t1.type == lexer::token::e_mul ) &&
+ (t2.type == lexer::token::e_rsqrbracket)
+ )
+ {
+ t.type = lexer::token::e_symbol;
+ t.value = "[*]";
+ t.position = t0.position;
+
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ class bracket_checker : public lexer::token_scanner
+ {
+ public:
+
+ using lexer::token_scanner::operator();
+
+ bracket_checker()
+ : token_scanner(1),
+ state_(true)
+ {}
+
+ bool result()
+ {
+ if (!stack_.empty())
+ {
+ lexer::token t;
+ t.value = stack_.top().first;
+ t.position = stack_.top().second;
+ error_token_ = t;
+ state_ = false;
+
+ return false;
+ }
+ else
+ return state_;
+ }
+
+ lexer::token error_token()
+ {
+ return error_token_;
+ }
+
+ void reset()
+ {
+ // Why? because msvc doesn't support swap properly.
+ stack_ = std::stack<std::pair<char,std::size_t> >();
+ state_ = true;
+ error_token_.clear();
+ }
+
+ bool operator() (const lexer::token& t)
+ {
+ if (
+ !t.value.empty() &&
+ (lexer::token::e_string != t.type) &&
+ (lexer::token::e_symbol != t.type) &&
+ exprtk::details::is_bracket(t.value[0])
+ )
+ {
+ details::char_t c = t.value[0];
+
+ if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position));
+ else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position));
+ else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position));
+ else if (exprtk::details::is_right_bracket(c))
+ {
+ if (stack_.empty())
+ {
+ state_ = false;
+ error_token_ = t;
+
+ return false;
+ }
+ else if (c != stack_.top().first)
+ {
+ state_ = false;
+ error_token_ = t;
+
+ return false;
+ }
+ else
+ stack_.pop();
+ }
+ }
+
+ return true;
+ }
+
+ private:
+
+ bool state_;
+ std::stack<std::pair<char,std::size_t> > stack_;
+ lexer::token error_token_;
+ };
+
+ class numeric_checker : public lexer::token_scanner
+ {
+ public:
+
+ using lexer::token_scanner::operator();
+
+ numeric_checker()
+ : token_scanner (1),
+ current_index_(0)
+ {}
+
+ bool result()
+ {
+ return error_list_.empty();
+ }
+
+ void reset()
+ {
+ error_list_.clear();
+ current_index_ = 0;
+ }
+
+ bool operator() (const lexer::token& t)
+ {
+ if (token::e_number == t.type)
+ {
+ double v;
+
+ if (!exprtk::details::string_to_real(t.value,v))
+ {
+ error_list_.push_back(current_index_);
+ }
+ }
+
+ ++current_index_;
+
+ return true;
+ }
+
+ std::size_t error_count() const
+ {
+ return error_list_.size();
+ }
+
+ std::size_t error_index(const std::size_t& i)
+ {
+ if (i < error_list_.size())
+ return error_list_[i];
+ else
+ return std::numeric_limits<std::size_t>::max();
+ }
+
+ void clear_errors()
+ {
+ error_list_.clear();
+ }
+
+ private:
+
+ std::size_t current_index_;
+ std::vector<std::size_t> error_list_;
+ };
+
+ class symbol_replacer : public lexer::token_modifier
+ {
+ private:
+
+ typedef std::map<std::string,std::pair<std::string,token::token_type>,details::ilesscompare> replace_map_t;
+
+ public:
+
+ bool remove(const std::string& target_symbol)
+ {
+ const 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)
+ {
+ const 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;
+
+ const replace_map_t::iterator itr = replace_map_.find(t.value);
+
+ if (replace_map_.end() != itr)
+ {
+ t.value = itr->second.first;
+ t.type = itr->second.second;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ replace_map_t replace_map_;
+ };
+
+ class sequence_validator : public lexer::token_scanner
+ {
+ private:
+
+ typedef std::pair<lexer::token::token_type,lexer::token::token_type> token_pair_t;
+ typedef std::set<token_pair_t> set_t;
+
+ public:
+
+ using lexer::token_scanner::operator();
+
+ sequence_validator()
+ : lexer::token_scanner(2)
+ {
+ add_invalid(lexer::token::e_number, lexer::token::e_number);
+ add_invalid(lexer::token::e_string, lexer::token::e_string);
+ add_invalid(lexer::token::e_number, lexer::token::e_string);
+ add_invalid(lexer::token::e_string, lexer::token::e_number);
+
+ add_invalid_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)
+ {
+ const 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() const
+ {
+ 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 (')' != base);
+ 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_;
+ };
+
+ class sequence_validator_3tokens : public lexer::token_scanner
+ {
+ private:
+
+ typedef lexer::token::token_type token_t;
+ typedef std::pair<token_t,std::pair<token_t,token_t> > token_triplet_t;
+ typedef std::set<token_triplet_t> set_t;
+
+ public:
+
+ using lexer::token_scanner::operator();
+
+ sequence_validator_3tokens()
+ : lexer::token_scanner(3)
+ {
+ add_invalid(lexer::token::e_number, lexer::token::e_number, lexer::token::e_number);
+ add_invalid(lexer::token::e_string, lexer::token::e_string, lexer::token::e_string);
+ add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma );
+
+ add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add );
+ add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub );
+ add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div );
+ add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul );
+ add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod );
+ add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow );
+
+ add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add );
+ add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub );
+ add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div );
+ add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul );
+ add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod );
+ add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow );
+ }
+
+ bool result()
+ {
+ return error_list_.empty();
+ }
+
+ bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2)
+ {
+ const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type));
+
+ if (invalid_comb_.find(p) != invalid_comb_.end())
+ {
+ error_list_.push_back(std::make_pair(t0,t1));
+ }
+
+ return true;
+ }
+
+ std::size_t error_count() const
+ {
+ 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(token_t t0, token_t t1, token_t t2)
+ {
+ invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2)));
+ }
+
+ set_t invalid_comb_;
+ std::vector<std::pair<lexer::token,lexer::token> > error_list_;
+ };
+
+ struct helper_assembly
+ {
+ inline bool register_scanner(lexer::token_scanner* scanner)
+ {
+ if (token_scanner_list.end() != std::find(token_scanner_list.begin(),
+ token_scanner_list.end (),
+ scanner))
+ {
+ return false;
+ }
+
+ token_scanner_list.push_back(scanner);
+
+ return true;
+ }
+
+ inline bool register_modifier(lexer::token_modifier* modifier)
+ {
+ if (token_modifier_list.end() != std::find(token_modifier_list.begin(),
+ token_modifier_list.end (),
+ modifier))
+ {
+ return false;
+ }
+
+ token_modifier_list.push_back(modifier);
+
+ return true;
+ }
+
+ inline bool register_joiner(lexer::token_joiner* joiner)
+ {
+ if (token_joiner_list.end() != std::find(token_joiner_list.begin(),
+ token_joiner_list.end (),
+ joiner))
+ {
+ return false;
+ }
+
+ token_joiner_list.push_back(joiner);
+
+ return true;
+ }
+
+ inline bool register_inserter(lexer::token_inserter* inserter)
+ {
+ if (token_inserter_list.end() != std::find(token_inserter_list.begin(),
+ token_inserter_list.end (),
+ inserter))
+ {
+ return false;
+ }
+
+ token_inserter_list.push_back(inserter);
+
+ return true;
+ }
+
+ inline bool run_modifiers(lexer::generator& g)
+ {
+ error_token_modifier = reinterpret_cast<lexer::token_modifier*>(0);
+
+ for (std::size_t i = 0; i < token_modifier_list.size(); ++i)
+ {
+ lexer::token_modifier& modifier = (*token_modifier_list[i]);
+
+ modifier.reset();
+ modifier.process(g);
+
+ if (!modifier.result())
+ {
+ error_token_modifier = token_modifier_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_joiners(lexer::generator& g)
+ {
+ error_token_joiner = reinterpret_cast<lexer::token_joiner*>(0);
+
+ for (std::size_t i = 0; i < token_joiner_list.size(); ++i)
+ {
+ lexer::token_joiner& joiner = (*token_joiner_list[i]);
+
+ joiner.reset();
+ joiner.process(g);
+
+ if (!joiner.result())
+ {
+ error_token_joiner = token_joiner_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_inserters(lexer::generator& g)
+ {
+ error_token_inserter = reinterpret_cast<lexer::token_inserter*>(0);
+
+ for (std::size_t i = 0; i < token_inserter_list.size(); ++i)
+ {
+ lexer::token_inserter& inserter = (*token_inserter_list[i]);
+
+ inserter.reset();
+ inserter.process(g);
+
+ if (!inserter.result())
+ {
+ error_token_inserter = token_inserter_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_scanners(lexer::generator& g)
+ {
+ error_token_scanner = reinterpret_cast<lexer::token_scanner*>(0);
+
+ for (std::size_t i = 0; i < token_scanner_list.size(); ++i)
+ {
+ lexer::token_scanner& scanner = (*token_scanner_list[i]);
+
+ scanner.reset();
+ scanner.process(g);
+
+ if (!scanner.result())
+ {
+ error_token_scanner = token_scanner_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ std::vector<lexer::token_scanner*> token_scanner_list;
+ std::vector<lexer::token_modifier*> token_modifier_list;
+ std::vector<lexer::token_joiner*> token_joiner_list;
+ std::vector<lexer::token_inserter*> token_inserter_list;
+
+ lexer::token_scanner* error_token_scanner;
+ lexer::token_modifier* error_token_modifier;
+ lexer::token_joiner* error_token_joiner;
+ lexer::token_inserter* error_token_inserter;
+ };
+ }
+
+ class parser_helper
+ {
+ public:
+
+ typedef token token_t;
+ typedef generator generator_t;
+
+ inline bool init(const std::string& str)
+ {
+ if (!lexer_.process(str))
+ {
+ return false;
+ }
+
+ lexer_.begin();
+
+ next_token();
+
+ return true;
+ }
+
+ inline generator_t& lexer()
+ {
+ return lexer_;
+ }
+
+ inline const generator_t& lexer() const
+ {
+ return lexer_;
+ }
+
+ inline void store_token()
+ {
+ lexer_.store();
+ store_current_token_ = current_token_;
+ }
+
+ inline void restore_token()
+ {
+ lexer_.restore();
+ current_token_ = store_current_token_;
+ }
+
+ inline void next_token()
+ {
+ current_token_ = lexer_.next_token();
+ }
+
+ inline const token_t& current_token() const
+ {
+ return current_token_;
+ }
+
+ enum token_advance_mode
+ {
+ e_hold = 0,
+ e_advance = 1
+ };
+
+ inline void advance_token(const token_advance_mode mode)
+ {
+ if (e_advance == mode)
+ {
+ next_token();
+ }
+ }
+
+ inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance)
+ {
+ if (current_token().type != ttype)
+ {
+ return false;
+ }
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ inline bool token_is(const token_t::token_type& ttype,
+ const std::string& value,
+ const token_advance_mode mode = e_advance)
+ {
+ if (
+ (current_token().type != ttype) ||
+ !exprtk::details::imatch(value,current_token().value)
+ )
+ {
+ return false;
+ }
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ inline bool peek_token_is(const token_t::token_type& ttype)
+ {
+ return (lexer_.peek_next_token().type == ttype);
+ }
+
+ inline bool peek_token_is(const std::string& s)
+ {
+ return (exprtk::details::imatch(lexer_.peek_next_token().value,s));
+ }
+
+ private:
+
+ generator_t lexer_;
+ token_t current_token_;
+ token_t store_current_token_;
+ };
+ }
+
+ template <typename T>
+ class vector_view
+ {
+ public:
+
+ typedef T* data_ptr_t;
+
+ vector_view(data_ptr_t data, const std::size_t& size)
+ : size_(size),
+ data_(data),
+ data_ref_(0)
+ {}
+
+ vector_view(const vector_view<T>& vv)
+ : size_(vv.size_),
+ data_(vv.data_),
+ data_ref_(0)
+ {}
+
+ inline void rebase(data_ptr_t data)
+ {
+ data_ = data;
+
+ if (!data_ref_.empty())
+ {
+ for (std::size_t i = 0; i < data_ref_.size(); ++i)
+ {
+ (*data_ref_[i]) = data;
+ }
+ }
+ }
+
+ inline data_ptr_t data() const
+ {
+ return data_;
+ }
+
+ inline std::size_t size() const
+ {
+ return size_;
+ }
+
+ inline const T& operator[](const std::size_t index) const
+ {
+ return data_[index];
+ }
+
+ inline T& operator[](const std::size_t index)
+ {
+ return data_[index];
+ }
+
+ void set_ref(data_ptr_t* data_ref)
+ {
+ data_ref_.push_back(data_ref);
+ }
+
+ private:
+
+ const std::size_t size_;
+ data_ptr_t data_;
+ std::vector<data_ptr_t*> data_ref_;
+ };
+
+ template <typename T>
+ inline vector_view<T> make_vector_view(T* data,
+ const std::size_t size, const std::size_t offset = 0)
+ {
+ return vector_view<T>(data + offset, size);
+ }
+
+ template <typename T>
+ inline vector_view<T> make_vector_view(std::vector<T>& v,
+ const std::size_t size, const std::size_t offset = 0)
+ {
+ return vector_view<T>(v.data() + offset, size);
+ }
+
+ template <typename T> class results_context;
+
+ template <typename T>
+ struct type_store
+ {
+ enum store_type
+ {
+ e_unknown,
+ e_scalar ,
+ e_vector ,
+ e_string
+ };
+
+ type_store()
+ : data(0),
+ size(0),
+ type(e_unknown)
+ {}
+
+ union
+ {
+ void* data;
+ T* vec_data;
+ };
+
+ std::size_t size;
+ store_type type;
+
+ class parameter_list
+ {
+ public:
+
+ parameter_list(std::vector<type_store>& pl)
+ : parameter_list_(pl)
+ {}
+
+ inline bool empty() const
+ {
+ return parameter_list_.empty();
+ }
+
+ inline std::size_t size() const
+ {
+ return parameter_list_.size();
+ }
+
+ inline type_store& operator[](const std::size_t& index)
+ {
+ return parameter_list_[index];
+ }
+
+ inline const type_store& operator[](const std::size_t& index) const
+ {
+ return parameter_list_[index];
+ }
+
+ inline type_store& front()
+ {
+ return parameter_list_[0];
+ }
+
+ inline const type_store& front() const
+ {
+ return parameter_list_[0];
+ }
+
+ inline type_store& back()
+ {
+ return parameter_list_.back();
+ }
+
+ inline const type_store& back() const
+ {
+ return parameter_list_.back();
+ }
+
+ private:
+
+ std::vector<type_store>& parameter_list_;
+
+ friend class results_context<T>;
+ };
+
+ template <typename ViewType>
+ struct type_view
+ {
+ typedef type_store<T> type_store_t;
+ typedef ViewType value_t;
+
+ type_view(type_store_t& ts)
+ : ts_(ts),
+ data_(reinterpret_cast<value_t*>(ts_.data))
+ {}
+
+ type_view(const type_store_t& ts)
+ : ts_(const_cast<type_store_t&>(ts)),
+ data_(reinterpret_cast<value_t*>(ts_.data))
+ {}
+
+ inline std::size_t size() const
+ {
+ return ts_.size;
+ }
+
+ inline value_t& operator[](const std::size_t& i)
+ {
+ return data_[i];
+ }
+
+ inline const value_t& operator[](const std::size_t& i) const
+ {
+ return data_[i];
+ }
+
+ inline const value_t* begin() const { return data_; }
+ inline value_t* begin() { return data_; }
+
+ inline const value_t* end() const
+ {
+ return static_cast<value_t*>(data_ + ts_.size);
+ }
+
+ inline value_t* end()
+ {
+ return static_cast<value_t*>(data_ + ts_.size);
+ }
+
+ type_store_t& ts_;
+ value_t* data_;
+ };
+
+ typedef type_view<T> vector_view;
+ typedef type_view<char> string_view;
+
+ struct scalar_view
+ {
+ typedef type_store<T> type_store_t;
+ typedef T value_t;
+
+ scalar_view(type_store_t& ts)
+ : v_(*reinterpret_cast<value_t*>(ts.data))
+ {}
+
+ scalar_view(const type_store_t& ts)
+ : v_(*reinterpret_cast<value_t*>(const_cast<type_store_t&>(ts).data))
+ {}
+
+ inline value_t& operator() ()
+ {
+ return v_;
+ }
+
+ inline const value_t& operator() () const
+ {
+ return v_;
+ }
+
+ template <typename IntType>
+ inline bool to_int(IntType& i) const
+ {
+ if (!exprtk::details::numeric::is_integer(v_))
+ return false;
+
+ i = static_cast<IntType>(v_);
+
+ return true;
+ }
+
+ template <typename UIntType>
+ inline bool to_uint(UIntType& u) const
+ {
+ if (v_ < T(0))
+ return false;
+ else if (!exprtk::details::numeric::is_integer(v_))
+ return false;
+
+ u = static_cast<UIntType>(v_);
+
+ return true;
+ }
+
+ T& v_;
+ };
+ };
+
+ template <typename StringView>
+ inline std::string to_str(const StringView& view)
+ {
+ return std::string(view.begin(),view.size());
+ }
+
+ #ifndef exprtk_disable_return_statement
+ namespace details
+ {
+ template <typename T> class return_node;
+ template <typename T> class return_envelope_node;
+ }
+ #endif
+
+ template <typename T>
+ class results_context
+ {
+ public:
+
+ typedef type_store<T> type_store_t;
+
+ results_context()
+ : results_available_(false)
+ {}
+
+ inline std::size_t count() const
+ {
+ if (results_available_)
+ return parameter_list_.size();
+ else
+ return 0;
+ }
+
+ inline type_store_t& operator[](const std::size_t& index)
+ {
+ return parameter_list_[index];
+ }
+
+ inline const type_store_t& operator[](const std::size_t& index) const
+ {
+ return parameter_list_[index];
+ }
+
+ private:
+
+ inline void clear()
+ {
+ results_available_ = false;
+ }
+
+ typedef std::vector<type_store_t> ts_list_t;
+ typedef typename type_store_t::parameter_list parameter_list_t;
+
+ inline void assign(const parameter_list_t& pl)
+ {
+ parameter_list_ = pl.parameter_list_;
+ results_available_ = true;
+ }
+
+ bool results_available_;
+ ts_list_t parameter_list_;
+
+ #ifndef exprtk_disable_return_statement
+ friend class details::return_node<T>;
+ friend class details::return_envelope_node<T>;
+ #endif
+ };
+
+ 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_smulti ,
+ e_swap ,
+
+ // Do not add new functions/operators after this point.
+ e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003,
+ e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007,
+ e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011,
+ e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015,
+ e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019,
+ e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023,
+ e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027,
+ e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031,
+ e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035,
+ e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039,
+ e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043,
+ e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047,
+ e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051,
+ e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055,
+ e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059,
+ e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063,
+ e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067,
+ e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071,
+ e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075,
+ e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079,
+ e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083,
+ e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087,
+ e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091,
+ e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095,
+ e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099,
+ e_sffinal = 1100,
+ e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003,
+ e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007,
+ e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011,
+ e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015,
+ e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019,
+ e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023,
+ e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027,
+ e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031,
+ e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035,
+ e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039,
+ e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043,
+ e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047,
+ e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051,
+ e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055,
+ e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059,
+ e_sf4ext60 = 2060, e_sf4ext61 = 2061
+ };
+
+ inline std::string to_str(const operator_type opr)
+ {
+ switch (opr)
+ {
+ case e_add : return "+" ;
+ case e_sub : return "-" ;
+ case e_mul : return "*" ;
+ case e_div : return "/" ;
+ case e_mod : return "%" ;
+ case e_pow : return "^" ;
+ case e_assign : return ":=" ;
+ case e_addass : return "+=" ;
+ case e_subass : return "-=" ;
+ case e_mulass : return "*=" ;
+ case e_divass : return "/=" ;
+ case e_modass : return "%=" ;
+ case e_lt : return "<" ;
+ case e_lte : return "<=" ;
+ case e_eq : return "==" ;
+ case e_equal : return "=" ;
+ case e_ne : return "!=" ;
+ case e_nequal : return "<>" ;
+ case e_gte : return ">=" ;
+ case e_gt : return ">" ;
+ case e_and : return "and" ;
+ case e_or : return "or" ;
+ case e_xor : return "xor" ;
+ case e_nand : return "nand";
+ case e_nor : return "nor" ;
+ case e_xnor : return "xnor";
+ default : return "N/A" ;
+ }
+ }
+
+ struct base_operation_t
+ {
+ base_operation_t(const operator_type t, const unsigned int& np)
+ : type(t),
+ num_params(np)
+ {}
+
+ operator_type type;
+ unsigned int num_params;
+ };
+
+ namespace loop_unroll
+ {
+ #ifndef exprtk_disable_superscalar_unroll
+ const unsigned int global_loop_batch_size = 16;
+ #else
+ const unsigned int global_loop_batch_size = 4;
+ #endif
+
+ struct details
+ {
+ details(const std::size_t& vsize,
+ const unsigned int loop_batch_size = global_loop_batch_size)
+ : batch_size(loop_batch_size ),
+ remainder (vsize % batch_size),
+ upper_bound(static_cast<int>(vsize - (remainder ? loop_batch_size : 0)))
+ {}
+
+ unsigned int batch_size;
+ int remainder;
+ int upper_bound;
+ };
+ }
+
+ #ifdef exprtk_enable_debugging
+ inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0)
+ {
+ if (size)
+ exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr));
+ else
+ exprtk_debug(("%s - addr: %p size: %d\n",
+ s.c_str(),
+ ptr,
+ static_cast<unsigned int>(size)));
+ }
+ #else
+ inline void dump_ptr(const std::string&, const void*) {}
+ inline void dump_ptr(const std::string&, const void*, const std::size_t) {}
+ #endif
+
+ template <typename T>
+ class vec_data_store
+ {
+ public:
+
+ typedef vec_data_store<T> type;
+ typedef T* data_t;
+
+ private:
+
+ struct control_block
+ {
+ control_block()
+ : ref_count(1),
+ size (0),
+ data (0),
+ destruct (true)
+ {}
+
+ control_block(const std::size_t& dsize)
+ : ref_count(1 ),
+ size (dsize),
+ data (0 ),
+ destruct (true )
+ { create_data(); }
+
+ control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false)
+ : ref_count(1 ),
+ size (dsize ),
+ data (dptr ),
+ destruct (dstrct)
+ {}
+
+ ~control_block()
+ {
+ if (data && destruct && (0 == ref_count))
+ {
+ dump_ptr("~control_block() data",data);
+ delete[] data;
+ data = reinterpret_cast<data_t>(0);
+ }
+ }
+
+ static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false)
+ {
+ if (dsize)
+ {
+ if (0 == data_ptr)
+ return (new control_block(dsize));
+ else
+ return (new control_block(dsize, data_ptr, dstrct));
+ }
+ else
+ return (new control_block);
+ }
+
+ static inline void destroy(control_block*& cntrl_blck)
+ {
+ if (cntrl_blck)
+ {
+ if (
+ (0 != cntrl_blck->ref_count) &&
+ (0 == --cntrl_blck->ref_count)
+ )
+ {
+ delete cntrl_blck;
+ }
+
+ cntrl_blck = 0;
+ }
+ }
+
+ std::size_t ref_count;
+ std::size_t size;
+ data_t data;
+ bool destruct;
+
+ private:
+
+ control_block(const control_block&);
+ control_block& operator=(const control_block&);
+
+ inline void create_data()
+ {
+ destruct = true;
+ data = new T[size];
+ std::fill_n(data,size,T(0));
+ dump_ptr("control_block::create_data() - data",data,size);
+ }
+ };
+
+ public:
+
+ vec_data_store()
+ : control_block_(control_block::create(0))
+ {}
+
+ vec_data_store(const std::size_t& size)
+ : control_block_(control_block::create(size,(data_t)(0),true))
+ {}
+
+ vec_data_store(const std::size_t& size, data_t data, bool dstrct = false)
+ : control_block_(control_block::create(size, data, dstrct))
+ {}
+
+ vec_data_store(const type& vds)
+ {
+ control_block_ = vds.control_block_;
+ control_block_->ref_count++;
+ }
+
+ ~vec_data_store()
+ {
+ control_block::destroy(control_block_);
+ }
+
+ type& operator=(const type& vds)
+ {
+ if (this != &vds)
+ {
+ std::size_t final_size = min_size(control_block_, vds.control_block_);
+
+ vds.control_block_->size = final_size;
+ control_block_->size = final_size;
+
+ if (control_block_->destruct || (0 == control_block_->data))
+ {
+ control_block::destroy(control_block_);
+
+ control_block_ = vds.control_block_;
+ control_block_->ref_count++;
+ }
+ }
+
+ return (*this);
+ }
+
+ inline data_t data()
+ {
+ return control_block_->data;
+ }
+
+ inline data_t data() const
+ {
+ return control_block_->data;
+ }
+
+ inline std::size_t size()
+ {
+ return control_block_->size;
+ }
+
+ inline std::size_t size() const
+ {
+ return control_block_->size;
+ }
+
+ inline data_t& ref()
+ {
+ return control_block_->data;
+ }
+
+ inline void dump() const
+ {
+ #ifdef exprtk_enable_debugging
+ exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n",
+ size(),
+ data(),
+ (control_block_->destruct ? 'T' : 'F')));
+
+ for (std::size_t i = 0; i < size(); ++i)
+ {
+ if (5 == i)
+ exprtk_debug(("\n"));
+
+ exprtk_debug(("%15.10f ",data()[i]));
+ }
+ exprtk_debug(("\n"));
+ #endif
+ }
+
+ static inline void match_sizes(type& vds0, type& vds1)
+ {
+ std::size_t size = min_size(vds0.control_block_,vds1.control_block_);
+ vds0.control_block_->size = size;
+ vds1.control_block_->size = size;
+ }
+
+ private:
+
+ static inline std::size_t min_size(control_block* cb0, control_block* cb1)
+ {
+ const std::size_t size0 = cb0->size;
+ const std::size_t size1 = cb1->size;
+
+ if (size0 && size1)
+ return std::min(size0,size1);
+ else
+ return (size0) ? size0 : size1;
+ }
+
+ control_block* control_block_;
+ };
+
+ namespace numeric
+ {
+ namespace details
+ {
+ template <typename T>
+ inline T process_impl(const operator_type operation, const T arg)
+ {
+ switch (operation)
+ {
+ case e_abs : return numeric::abs (arg);
+ case e_acos : return numeric::acos (arg);
+ case e_acosh : return numeric::acosh(arg);
+ case e_asin : return numeric::asin (arg);
+ case e_asinh : return numeric::asinh(arg);
+ case e_atan : return numeric::atan (arg);
+ case e_atanh : return numeric::atanh(arg);
+ case e_ceil : return numeric::ceil (arg);
+ case e_cos : return numeric::cos (arg);
+ case e_cosh : return numeric::cosh (arg);
+ case e_exp : return numeric::exp (arg);
+ case e_expm1 : return numeric::expm1(arg);
+ case e_floor : return numeric::floor(arg);
+ case e_log : return numeric::log (arg);
+ case e_log10 : return numeric::log10(arg);
+ case e_log2 : return numeric::log2 (arg);
+ case e_log1p : return numeric::log1p(arg);
+ case e_neg : return numeric::neg (arg);
+ case e_pos : return numeric::pos (arg);
+ case e_round : return numeric::round(arg);
+ case e_sin : return numeric::sin (arg);
+ case e_sinc : return numeric::sinc (arg);
+ case e_sinh : return numeric::sinh (arg);
+ case e_sqrt : return numeric::sqrt (arg);
+ case e_tan : return numeric::tan (arg);
+ case e_tanh : return numeric::tanh (arg);
+ case e_cot : return numeric::cot (arg);
+ case e_sec : return numeric::sec (arg);
+ case e_csc : return numeric::csc (arg);
+ case e_r2d : return numeric::r2d (arg);
+ case e_d2r : return numeric::d2r (arg);
+ case e_d2g : return numeric::d2g (arg);
+ case e_g2d : return numeric::g2d (arg);
+ case e_notl : return numeric::notl (arg);
+ case e_sgn : return numeric::sgn (arg);
+ case e_erf : return numeric::erf (arg);
+ case e_erfc : return numeric::erfc (arg);
+ case e_ncdf : return numeric::ncdf (arg);
+ case e_frac : return numeric::frac (arg);
+ case e_trunc : return numeric::trunc(arg);
+
+ default : exprtk_debug(("numeric::details::process_impl<T> - Invalid unary operation.\n"));
+ 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 (arg0,arg1);
+ case e_nequal : return nequal (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 : exprtk_debug(("numeric::details::process_impl<T> - Invalid binary operation.\n"));
+ 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 : exprtk_debug(("numeric::details::process_impl<IntType> - Invalid binary operation.\n"));
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+ }
+ }
+
+ template <typename T>
+ inline T process(const operator_type operation, const T arg)
+ {
+ return exprtk::details::numeric::details::process_impl(operation,arg);
+ }
+
+ template <typename T>
+ inline T process(const operator_type operation, const T arg0, const T arg1)
+ {
+ return exprtk::details::numeric::details::process_impl(operation, arg0, arg1);
+ }
+ }
+
+ template <typename T>
+ class expression_node
+ {
+ public:
+
+ enum node_type
+ {
+ e_none , e_null , e_constant , e_unary ,
+ e_binary , e_binary_ext , e_trinary , e_quaternary ,
+ e_vararg , e_conditional , e_while , e_repeat ,
+ e_for , e_switch , e_mswitch , e_return ,
+ e_retenv , e_variable , e_stringvar , e_stringconst ,
+ e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat ,
+ e_stringvarsize , e_strswap , e_stringsize , e_stringvararg ,
+ e_function , e_vafunction , e_genfunction , e_strfunction ,
+ e_strcondition , e_strccondition , e_add , e_sub ,
+ e_mul , e_div , e_mod , e_pow ,
+ e_lt , e_lte , e_gt , e_gte ,
+ e_eq , e_ne , e_and , e_nand ,
+ e_or , e_nor , e_xor , e_xnor ,
+ e_in , e_like , e_ilike , e_inranges ,
+ e_ipow , e_ipowinv , e_abs , e_acos ,
+ e_acosh , e_asin , e_asinh , e_atan ,
+ e_atanh , e_ceil , e_cos , e_cosh ,
+ e_exp , e_expm1 , e_floor , e_log ,
+ e_log10 , e_log2 , e_log1p , e_neg ,
+ e_pos , e_round , e_sin , e_sinc ,
+ e_sinh , e_sqrt , e_tan , e_tanh ,
+ e_cot , e_sec , e_csc , e_r2d ,
+ e_d2r , e_d2g , e_g2d , e_notl ,
+ e_sgn , e_erf , e_erfc , e_ncdf ,
+ e_frac , e_trunc , e_uvouv , e_vov ,
+ e_cov , e_voc , e_vob , e_bov ,
+ e_cob , e_boc , e_vovov , e_vovoc ,
+ e_vocov , e_covov , e_covoc , e_vovovov ,
+ e_vovovoc , e_vovocov , e_vocovov , e_covovov ,
+ e_covocov , e_vocovoc , e_covovoc , e_vococov ,
+ e_sf3ext , e_sf4ext , e_nulleq , e_strass ,
+ e_vector , e_vecelem , e_rbvecelem , e_rbveccelem ,
+ e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass ,
+ e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq ,
+ e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith ,
+ e_valvecarith , e_vecunaryop , e_break , e_continue ,
+ e_swap
+ };
+
+ typedef T value_type;
+ typedef expression_node<T>* expression_ptr;
+
+ virtual ~expression_node()
+ {}
+
+ inline virtual T value() const
+ {
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ inline virtual expression_node<T>* branch(const std::size_t& index = 0) const
+ {
+ return reinterpret_cast<expression_ptr>(index * 0);
+ }
+
+ inline virtual node_type type() const
+ {
+ return e_none;
+ }
+ };
+
+ template <typename T>
+ inline bool is_generally_string_node(const expression_node<T>* node);
+
+ inline bool is_true(const double v)
+ {
+ return std::not_equal_to<double>()(0.0,v);
+ }
+
+ inline bool is_true(const long double v)
+ {
+ return std::not_equal_to<long double>()(0.0L,v);
+ }
+
+ inline bool is_true(const float v)
+ {
+ return std::not_equal_to<float>()(0.0f,v);
+ }
+
+ template <typename T>
+ inline bool is_true(const std::complex<T>& v)
+ {
+ return std::not_equal_to<std::complex<T> >()(std::complex<T>(0),v);
+ }
+
+ template <typename T>
+ inline bool is_true(const expression_node<T>* node)
+ {
+ return std::not_equal_to<T>()(T(0),node->value());
+ }
+
+ template <typename T>
+ inline bool is_false(const expression_node<T>* node)
+ {
+ return std::equal_to<T>()(T(0),node->value());
+ }
+
+ template <typename T>
+ inline bool is_unary_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_unary == node->type());
+ }
+
+ template <typename T>
+ inline bool is_neg_unary_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_neg == node->type());
+ }
+
+ template <typename T>
+ inline bool is_binary_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_binary == node->type());
+ }
+
+ template <typename T>
+ inline bool is_variable_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_variable == node->type());
+ }
+
+ template <typename T>
+ inline bool is_ivariable_node(const expression_node<T>* node)
+ {
+ return node &&
+ (
+ details::expression_node<T>::e_variable == node->type() ||
+ details::expression_node<T>::e_vecelem == node->type() ||
+ details::expression_node<T>::e_rbvecelem == node->type() ||
+ details::expression_node<T>::e_rbveccelem == node->type()
+ );
+ }
+
+ template <typename T>
+ inline bool is_vector_elem_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_vecelem == node->type());
+ }
+
+ template <typename T>
+ inline bool is_rebasevector_elem_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_rbvecelem == node->type());
+ }
+
+ template <typename T>
+ inline bool is_rebasevector_celem_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_rbveccelem == node->type());
+ }
+
+ template <typename T>
+ inline bool is_vector_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_vector == node->type());
+ }
+
+ template <typename T>
+ inline bool is_ivector_node(const expression_node<T>* node)
+ {
+ if (node)
+ {
+ switch (node->type())
+ {
+ case details::expression_node<T>::e_vector :
+ case details::expression_node<T>::e_vecvalass :
+ case details::expression_node<T>::e_vecvecass :
+ case details::expression_node<T>::e_vecopvalass :
+ case details::expression_node<T>::e_vecopvecass :
+ case details::expression_node<T>::e_vecvecswap :
+ case details::expression_node<T>::e_vecvecarith :
+ case details::expression_node<T>::e_vecvalarith :
+ case details::expression_node<T>::e_valvecarith :
+ case details::expression_node<T>::e_vecunaryop : return true;
+ default : return false;
+ }
+ }
+ else
+ return false;
+ }
+
+ template <typename T>
+ inline bool is_constant_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_constant == node->type());
+ }
+
+ template <typename T>
+ inline bool is_null_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_null == node->type());
+ }
+
+ template <typename T>
+ inline bool is_break_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_break == node->type());
+ }
+
+ template <typename T>
+ inline bool is_continue_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_continue == node->type());
+ }
+
+ template <typename T>
+ inline bool is_swap_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_swap == node->type());
+ }
+
+ template <typename T>
+ inline bool is_function(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_function == node->type());
+ }
+
+ template <typename T>
+ inline bool is_return_node(const expression_node<T>* node)
+ {
+ return node && (details::expression_node<T>::e_return == node->type());
+ }
+
+ template <typename T> class unary_node;
+
+ template <typename T>
+ inline bool is_negate_node(const expression_node<T>* node)
+ {
+ if (node && is_unary_node(node))
+ {
+ return (details::e_neg == static_cast<const unary_node<T>*>(node)->operation());
+ }
+ else
+ return false;
+ }
+
+ template <typename T>
+ inline bool branch_deletable(expression_node<T>* node)
+ {
+ return !is_variable_node(node) &&
+ !is_string_node (node) ;
+ }
+
+ template <std::size_t N, typename T>
+ inline bool all_nodes_valid(expression_node<T>* (&b)[N])
+ {
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ if (0 == b[i]) return false;
+ }
+
+ return true;
+ }
+
+ template <typename T,
+ typename Allocator,
+ template <typename, typename> class Sequence>
+ inline bool all_nodes_valid(const Sequence<expression_node<T>*,Allocator>& b)
+ {
+ for (std::size_t i = 0; i < b.size(); ++i)
+ {
+ if (0 == b[i]) return false;
+ }
+
+ return true;
+ }
+
+ template <std::size_t N, typename T>
+ inline bool all_nodes_variables(expression_node<T>* (&b)[N])
+ {
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ if (0 == b[i])
+ return false;
+ else if (!is_variable_node(b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename T,
+ typename Allocator,
+ template <typename, typename> class Sequence>
+ inline bool all_nodes_variables(Sequence<expression_node<T>*,Allocator>& b)
+ {
+ for (std::size_t i = 0; i < b.size(); ++i)
+ {
+ if (0 == b[i])
+ return false;
+ else if (!is_variable_node(b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename NodeAllocator, typename T, std::size_t N>
+ inline void free_all_nodes(NodeAllocator& node_allocator, expression_node<T>* (&b)[N])
+ {
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ free_node(node_allocator,b[i]);
+ }
+ }
+
+ template <typename NodeAllocator,
+ typename T,
+ typename Allocator,
+ template <typename, typename> class Sequence>
+ inline void free_all_nodes(NodeAllocator& node_allocator, Sequence<expression_node<T>*,Allocator>& b)
+ {
+ for (std::size_t i = 0; i < b.size(); ++i)
+ {
+ free_node(node_allocator,b[i]);
+ }
+
+ b.clear();
+ }
+
+ template <typename NodeAllocator, typename T>
+ inline void free_node(NodeAllocator& node_allocator, expression_node<T>*& node, const bool force_delete = false)
+ {
+ if (0 != node)
+ {
+ if (
+ (is_variable_node(node) || is_string_node(node)) ||
+ force_delete
+ )
+ return;
+
+ node_allocator.free(node);
+ node = reinterpret_cast<expression_node<T>*>(0);
+ }
+ }
+
+ template <typename T>
+ inline void destroy_node(expression_node<T>*& node)
+ {
+ delete node;
+ node = reinterpret_cast<expression_node<T>*>(0);
+ }
+
+ template <typename Type>
+ class vector_holder
+ {
+ private:
+
+ typedef Type value_type;
+ typedef value_type* value_ptr;
+ typedef const value_ptr const_value_ptr;
+
+ class vector_holder_base
+ {
+ public:
+
+ virtual ~vector_holder_base() {}
+
+ inline value_ptr operator[](const std::size_t& index) const
+ {
+ return value_at(index);
+ }
+
+ inline std::size_t size() const
+ {
+ return vector_size();
+ }
+
+ inline value_ptr data() const
+ {
+ return value_at(0);
+ }
+
+ virtual inline bool rebaseable() const
+ {
+ return false;
+ }
+
+ virtual void set_ref(value_ptr*) {}
+
+ protected:
+
+ virtual value_ptr value_at(const std::size_t&) const = 0;
+ virtual std::size_t vector_size() const = 0;
+ };
+
+ class array_vector_impl : public vector_holder_base
+ {
+ public:
+
+ array_vector_impl(const Type* vec, const std::size_t& vec_size)
+ : vec_(vec),
+ size_(vec_size)
+ {}
+
+ protected:
+
+ value_ptr value_at(const std::size_t& index) const
+ {
+ if (index < size_)
+ return const_cast<const_value_ptr>(vec_ + index);
+ else
+ return const_value_ptr(0);
+ }
+
+ std::size_t vector_size() const
+ {
+ return size_;
+ }
+
+ private:
+
+ array_vector_impl operator=(const array_vector_impl&);
+
+ const Type* vec_;
+ const std::size_t size_;
+ };
+
+ template <typename Allocator,
+ template <typename, typename> class Sequence>
+ class sequence_vector_impl : public vector_holder_base
+ {
+ public:
+
+ typedef Sequence<Type,Allocator> sequence_t;
+
+ sequence_vector_impl(sequence_t& seq)
+ : sequence_(seq)
+ {}
+
+ protected:
+
+ value_ptr value_at(const std::size_t& index) const
+ {
+ return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0);
+ }
+
+ std::size_t vector_size() const
+ {
+ return sequence_.size();
+ }
+
+ private:
+
+ sequence_vector_impl operator=(const sequence_vector_impl&);
+
+ sequence_t& sequence_;
+ };
+
+ class vector_view_impl : public vector_holder_base
+ {
+ public:
+
+ typedef exprtk::vector_view<Type> vector_view_t;
+
+ vector_view_impl(vector_view_t& vec_view)
+ : vec_view_(vec_view)
+ {}
+
+ void set_ref(value_ptr* ref)
+ {
+ vec_view_.set_ref(ref);
+ }
+
+ virtual inline bool rebaseable() const
+ {
+ return true;
+ }
+
+ protected:
+
+ value_ptr value_at(const std::size_t& index) const
+ {
+ return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0);
+ }
+
+ std::size_t vector_size() const
+ {
+ return vec_view_.size();
+ }
+
+ private:
+
+ vector_view_impl operator=(const vector_view_impl&);
+
+ vector_view_t& vec_view_;
+ };
+
+ public:
+
+ typedef typename details::vec_data_store<Type> vds_t;
+
+ vector_holder(Type* vec, const std::size_t& vec_size)
+ : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size))
+ {}
+
+ vector_holder(const vds_t& vds)
+ : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size()))
+ {}
+
+ template <typename Allocator>
+ vector_holder(std::vector<Type,Allocator>& vec)
+ : vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::vector>(vec))
+ {}
+
+ vector_holder(exprtk::vector_view<Type>& vec)
+ : vector_holder_base_(new(buffer)vector_view_impl(vec))
+ {}
+
+ inline value_ptr operator[](const std::size_t& index) const
+ {
+ return (*vector_holder_base_)[index];
+ }
+
+ inline std::size_t size() const
+ {
+ return vector_holder_base_->size();
+ }
+
+ inline value_ptr data() const
+ {
+ return vector_holder_base_->data();
+ }
+
+ void set_ref(value_ptr* ref)
+ {
+ vector_holder_base_->set_ref(ref);
+ }
+
+ bool rebaseable() const
+ {
+ return vector_holder_base_->rebaseable();
+ }
+
+ private:
+
+ mutable vector_holder_base* vector_holder_base_;
+ uchar_t buffer[64];
+ };
+
+ template <typename T>
+ class null_node : public expression_node<T>
+ {
+ public:
+
+ inline T value() const
+ {
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_null;
+ }
+ };
+
+ template <typename T>
+ class null_eq_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ null_eq_node(expression_ptr brnch, const bool equality = true)
+ : branch_(brnch),
+ branch_deletable_(branch_deletable(branch_)),
+ equality_(equality)
+ {}
+
+ ~null_eq_node()
+ {
+ if (branch_ && branch_deletable_)
+ {
+ destroy_node(branch_);
+ }
+ }
+
+ 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_;
+ const bool branch_deletable_;
+ bool equality_;
+ };
+
+ template <typename T>
+ class literal_node : public expression_node<T>
+ {
+ public:
+
+ explicit literal_node(const T& v)
+ : value_(v)
+ {}
+
+ inline T value() const
+ {
+ return value_;
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_constant;
+ }
+
+ inline expression_node<T>* branch(const std::size_t&) const
+ {
+ return reinterpret_cast<expression_node<T>*>(0);
+ }
+
+ private:
+
+ literal_node(literal_node<T>&) {}
+ literal_node<T>& operator=(literal_node<T>&) { return (*this); }
+
+ const T value_;
+ };
+
+ template <typename T>
+ struct range_pack;
+
+ template <typename T>
+ struct range_data_type;
+
+ template <typename T>
+ class range_interface
+ {
+ public:
+
+ typedef range_pack<T> range_t;
+
+ virtual ~range_interface()
+ {}
+
+ virtual range_t& range_ref() = 0;
+
+ virtual const range_t& range_ref() const = 0;
+ };
+
+ #ifndef exprtk_disable_string_capabilities
+ template <typename T>
+ class string_base_node
+ {
+ public:
+
+ typedef range_data_type<T> range_data_type_t;
+
+ virtual ~string_base_node()
+ {}
+
+ virtual std::string str () const = 0;
+
+ virtual char_cptr 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_;
+ }
+
+ char_cptr 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_;
+ };
+ #endif
+
+ 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_)
+ {
+ destroy_node(branch_);
+ }
+ }
+
+ 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)
+ {
+ destroy_node(branch[i].first);
+ }
+ }
+ }
+
+ 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)
+ {
+ destroy_node(branch[i].first);
+ }
+ }
+ }
+ };
+
+ template <typename T>
+ class binary_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef std::pair<expression_ptr,bool> branch_t;
+
+ binary_node(const operator_type& opr,
+ expression_ptr branch0,
+ expression_ptr branch1)
+ : operation_(opr)
+ {
+ init_branches<2>(branch_, branch0, branch1);
+ }
+
+ ~binary_node()
+ {
+ cleanup_branches::execute<T,2>(branch_);
+ }
+
+ inline T value() const
+ {
+ const T arg0 = branch_[0].first->value();
+ const T arg1 = branch_[1].first->value();
+
+ return numeric::process<T>(operation_,arg0,arg1);
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_binary;
+ }
+
+ inline operator_type operation()
+ {
+ return operation_;
+ }
+
+ inline expression_node<T>* branch(const std::size_t& index = 0) const
+ {
+ if (0 == index)
+ return branch_[0].first;
+ else if (1 == index)
+ return branch_[1].first;
+ else
+ return reinterpret_cast<expression_ptr>(0);
+ }
+
+ protected:
+
+ operator_type operation_;
+ branch_t branch_[2];
+ };
+
+ template <typename T, typename Operation>
+ class binary_ext_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef std::pair<expression_ptr,bool> branch_t;
+
+ binary_ext_node(expression_ptr branch0, expression_ptr branch1)
+ {
+ init_branches<2>(branch_, branch0, branch1);
+ }
+
+ ~binary_ext_node()
+ {
+ cleanup_branches::execute<T,2>(branch_);
+ }
+
+ inline T value() const
+ {
+ const T arg0 = branch_[0].first->value();
+ const T arg1 = branch_[1].first->value();
+
+ return Operation::process(arg0,arg1);
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_binary_ext;
+ }
+
+ inline operator_type operation()
+ {
+ return Operation::operation();
+ }
+
+ inline expression_node<T>* branch(const std::size_t& index = 0) const
+ {
+ if (0 == index)
+ return branch_[0].first;
+ else if (1 == index)
+ return branch_[1].first;
+ else
+ return reinterpret_cast<expression_ptr>(0);
+ }
+
+ protected:
+
+ branch_t branch_[2];
+ };
+
+ template <typename T>
+ class trinary_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef std::pair<expression_ptr,bool> branch_t;
+
+ trinary_node(const operator_type& opr,
+ expression_ptr branch0,
+ expression_ptr branch1,
+ expression_ptr branch2)
+ : operation_(opr)
+ {
+ init_branches<3>(branch_, branch0, branch1, branch2);
+ }
+
+ ~trinary_node()
+ {
+ cleanup_branches::execute<T,3>(branch_);
+ }
+
+ inline T value() const
+ {
+ const T arg0 = branch_[0].first->value();
+ const T arg1 = branch_[1].first->value();
+ const T arg2 = branch_[2].first->value();
+
+ switch (operation_)
+ {
+ case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1));
+
+ case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1);
+
+ case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2))
+ return arg1;
+ else
+ return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2);
+
+ default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n"));
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_trinary;
+ }
+
+ protected:
+
+ operator_type operation_;
+ branch_t branch_[3];
+ };
+
+ template <typename T>
+ class quaternary_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef std::pair<expression_ptr,bool> branch_t;
+
+ quaternary_node(const operator_type& opr,
+ expression_ptr branch0,
+ expression_ptr branch1,
+ expression_ptr branch2,
+ expression_ptr branch3)
+ : operation_(opr)
+ {
+ init_branches<4>(branch_, branch0, branch1, branch2, branch3);
+ }
+
+ ~quaternary_node()
+ {
+ cleanup_branches::execute<T,4>(branch_);
+ }
+
+ inline T value() const
+ {
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_quaternary;
+ }
+
+ protected:
+
+ operator_type operation_;
+ branch_t branch_[4];
+ };
+
+ template <typename T>
+ class conditional_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ conditional_node(expression_ptr test,
+ expression_ptr consequent,
+ expression_ptr alternative)
+ : test_(test),
+ consequent_(consequent),
+ alternative_(alternative),
+ test_deletable_(branch_deletable(test_)),
+ consequent_deletable_(branch_deletable(consequent_)),
+ alternative_deletable_(branch_deletable(alternative_))
+ {}
+
+ ~conditional_node()
+ {
+ if (test_ && test_deletable_)
+ {
+ destroy_node(test_);
+ }
+
+ if (consequent_ && consequent_deletable_ )
+ {
+ destroy_node(consequent_);
+ }
+
+ if (alternative_ && alternative_deletable_)
+ {
+ destroy_node(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_;
+ const bool test_deletable_;
+ const bool consequent_deletable_;
+ const 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_)
+ {
+ destroy_node(test_);
+ }
+
+ if (consequent_ && consequent_deletable_)
+ {
+ destroy_node(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_;
+ const bool test_deletable_;
+ const bool consequent_deletable_;
+ };
+
+ #ifndef exprtk_disable_break_continue
+ template <typename T>
+ class break_exception
+ {
+ public:
+
+ break_exception(const T& v)
+ : value(v)
+ {}
+
+ T value;
+ };
+
+ class continue_exception
+ {};
+
+ template <typename T>
+ class break_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ break_node(expression_ptr ret = expression_ptr(0))
+ : return_(ret),
+ return_deletable_(branch_deletable(return_))
+ {}
+
+ ~break_node()
+ {
+ if (return_deletable_)
+ {
+ destroy_node(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_;
+ const 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_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_;
+ const bool condition_deletable_;
+ const 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_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_;
+ const bool condition_deletable_;
+ const 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_)
+ {
+ destroy_node(initialiser_);
+ }
+
+ if (condition_ && condition_deletable_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (incrementor_ && incrementor_deletable_)
+ {
+ destroy_node(incrementor_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_ ;
+ const bool initialiser_deletable_;
+ const bool condition_deletable_ ;
+ const bool incrementor_deletable_;
+ const 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_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_;
+ const bool condition_deletable_;
+ const 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_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_;
+ const bool condition_deletable_;
+ const 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_)
+ {
+ destroy_node(initialiser_);
+ }
+
+ if (condition_ && condition_deletable_)
+ {
+ destroy_node(condition_);
+ }
+
+ if (incrementor_ && incrementor_deletable_)
+ {
+ destroy_node(incrementor_);
+ }
+
+ if (loop_body_ && loop_body_deletable_)
+ {
+ destroy_node(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_ ;
+ const bool initialiser_deletable_;
+ const bool condition_deletable_ ;
+ const bool incrementor_deletable_;
+ const 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>
+ explicit 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])
+ {
+ destroy_node(arg_list_[i]);
+ }
+ }
+ }
+
+ inline T value() const
+ {
+ if (!arg_list_.empty())
+ {
+ const std::size_t upper_bound = (arg_list_.size() - 1);
+
+ for (std::size_t i = 0; i < upper_bound; i += 2)
+ {
+ expression_ptr condition = arg_list_[i ];
+ expression_ptr consequent = arg_list_[i + 1];
+
+ if (is_true(condition))
+ {
+ return consequent->value();
+ }
+ }
+
+ return arg_list_[upper_bound]->value();
+ }
+ else
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_switch;
+ }
+
+ protected:
+
+ std::vector<expression_ptr> arg_list_;
+ std::vector<unsigned char> delete_branch_;
+ };
+
+ template <typename T, typename Switch_N>
+ class switch_n_node : public switch_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ template <typename Allocator,
+ template <typename, typename> class Sequence>
+ explicit switch_n_node(const Sequence<expression_ptr,Allocator>& arg_list)
+ : switch_node<T>(arg_list)
+ {}
+
+ inline T value() const
+ {
+ return Switch_N::process(switch_node<T>::arg_list_);
+ }
+ };
+
+ template <typename T>
+ class multi_switch_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ template <typename Allocator,
+ template <typename, typename> class Sequence>
+ explicit 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])
+ {
+ destroy_node(arg_list_[i]);
+ }
+ }
+ }
+
+ inline T value() const
+ {
+ T result = T(0);
+
+ if (arg_list_.empty())
+ {
+ return std::numeric_limits<T>::quiet_NaN();
+ }
+
+ const std::size_t upper_bound = (arg_list_.size() - 1);
+
+ for (std::size_t i = 0; i < upper_bound; i += 2)
+ {
+ expression_ptr condition = arg_list_[i ];
+ expression_ptr consequent = arg_list_[i + 1];
+
+ if (is_true(condition))
+ {
+ result = consequent->value();
+ }
+ }
+
+ return result;
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_mswitch;
+ }
+
+ private:
+
+ std::vector<expression_ptr> arg_list_;
+ std::vector<unsigned char> delete_branch_;
+ };
+
+ template <typename T>
+ class ivariable
+ {
+ public:
+
+ virtual ~ivariable()
+ {}
+
+ virtual T& ref() = 0;
+ virtual const T& ref() const = 0;
+ };
+
+ template <typename T>
+ class variable_node : public expression_node<T>,
+ public ivariable <T>
+ {
+ public:
+
+ static T null_value;
+
+ explicit variable_node()
+ : value_(&null_value)
+ {}
+
+ explicit variable_node(T& v)
+ : value_(&v)
+ {}
+
+ 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;
+ }
+
+ private:
+
+ T* 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)
+ )
+ {
+ destroy_node(n0_e.second);
+ }
+ }
+
+ if (n1_e.first && n1_e.second)
+ {
+ n1_e.first = false;
+
+ if (
+ !is_variable_node(n1_e.second) &&
+ !is_string_node (n1_e.second)
+ )
+ {
+ destroy_node(n1_e.second);
+ }
+ }
+ }
+
+ 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)
+ {
+ const 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)
+ {
+ const T r1_value = n1_e.second->value();
+
+ if (r1_value < 0)
+ return false;
+ else
+ r1 = static_cast<std::size_t>(details::numeric::to_int64(r1_value));
+ }
+ else
+ return false;
+
+ if (
+ (std::numeric_limits<std::size_t>::max() != size) &&
+ (std::numeric_limits<std::size_t>::max() == r1 )
+ )
+ {
+ r1 = size - 1;
+ }
+
+ cache.first = r0;
+ cache.second = r1;
+
+ return (r0 <= r1);
+ }
+
+ inline std::size_t const_size() const
+ {
+ return (n1_c.second - n0_c.second + 1);
+ }
+
+ inline std::size_t cache_size() const
+ {
+ return (cache.second - cache.first + 1);
+ }
+
+ std::pair<bool,expression_node_ptr> n0_e;
+ std::pair<bool,expression_node_ptr> n1_e;
+ std::pair<bool,std::size_t > n0_c;
+ std::pair<bool,std::size_t > n1_c;
+ mutable cached_range_t cache;
+ };
+
+ template <typename T>
+ class string_base_node;
+
+ template <typename T>
+ struct range_data_type
+ {
+ typedef range_pack<T> range_t;
+ typedef string_base_node<T>* strbase_ptr_t;
+
+ range_data_type()
+ : range(0),
+ data (0),
+ size (0),
+ type_size(0),
+ str_node (0)
+ {}
+
+ range_t* range;
+ void* data;
+ std::size_t size;
+ std::size_t type_size;
+ strbase_ptr_t str_node;
+ };
+
+ template <typename T> class vector_node;
+
+ template <typename T>
+ class vector_interface
+ {
+ public:
+
+ typedef vector_node<T>* vector_node_ptr;
+ typedef vec_data_store<T> vds_t;
+
+ virtual ~vector_interface()
+ {}
+
+ virtual std::size_t size () const = 0;
+
+ virtual vector_node_ptr vec() const = 0;
+
+ virtual vector_node_ptr vec() = 0;
+
+ virtual vds_t& vds () = 0;
+
+ virtual const vds_t& vds () const = 0;
+
+ virtual bool side_effect () const { return false; }
+ };
+
+ template <typename T>
+ class vector_node : public expression_node <T>,
+ public vector_interface<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef vector_holder<T> vector_holder_t;
+ typedef vector_node<T>* vector_node_ptr;
+ typedef vec_data_store<T> vds_t;
+
+ explicit vector_node(vector_holder_t* vh)
+ : vector_holder_(vh),
+ vds_((*vector_holder_).size(),(*vector_holder_)[0])
+ {
+ vector_holder_->set_ref(&vds_.ref());
+ }
+
+ vector_node(const vds_t& vds, vector_holder_t* vh)
+ : vector_holder_(vh),
+ vds_(vds)
+ {}
+
+ inline T value() const
+ {
+ return vds().data()[0];
+ }
+
+ vector_node_ptr vec() const
+ {
+ return const_cast<vector_node_ptr>(this);
+ }
+
+ vector_node_ptr vec()
+ {
+ return this;
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_vector;
+ }
+
+ std::size_t size() const
+ {
+ return vds().size();
+ }
+
+ vds_t& vds()
+ {
+ return vds_;
+ }
+
+ const vds_t& vds() const
+ {
+ return vds_;
+ }
+
+ inline vector_holder_t& vec_holder()
+ {
+ return (*vector_holder_);
+ }
+
+ private:
+
+ vector_holder_t* vector_holder_;
+ vds_t vds_;
+ };
+
+ template <typename T>
+ class vector_elem_node : public expression_node<T>,
+ public ivariable <T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef vector_holder<T> vector_holder_t;
+ typedef vector_holder_t* vector_holder_ptr;
+
+ vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder)
+ : index_(index),
+ vec_holder_(vec_holder),
+ vector_base_((*vec_holder)[0]),
+ index_deletable_(branch_deletable(index_))
+ {}
+
+ ~vector_elem_node()
+ {
+ if (index_ && index_deletable_)
+ {
+ destroy_node(index_);
+ }
+ }
+
+ inline T value() const
+ {
+ return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline T& ref()
+ {
+ return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline const T& ref() const
+ {
+ return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_vecelem;
+ }
+
+ inline vector_holder_t& vec_holder()
+ {
+ return (*vec_holder_);
+ }
+
+ private:
+
+ expression_ptr index_;
+ vector_holder_ptr vec_holder_;
+ T* vector_base_;
+ const bool index_deletable_;
+ };
+
+ template <typename T>
+ class rebasevector_elem_node : public expression_node<T>,
+ public ivariable <T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef vector_holder<T> vector_holder_t;
+ typedef vector_holder_t* vector_holder_ptr;
+ typedef vec_data_store<T> vds_t;
+
+ rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder)
+ : index_(index),
+ index_deletable_(branch_deletable(index_)),
+ vector_holder_(vec_holder),
+ vds_((*vector_holder_).size(),(*vector_holder_)[0])
+ {
+ vector_holder_->set_ref(&vds_.ref());
+ }
+
+ ~rebasevector_elem_node()
+ {
+ if (index_ && index_deletable_)
+ {
+ destroy_node(index_);
+ }
+ }
+
+ inline T value() const
+ {
+ return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline T& ref()
+ {
+ return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline const T& ref() const
+ {
+ return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_rbvecelem;
+ }
+
+ inline vector_holder_t& vec_holder()
+ {
+ return (*vector_holder_);
+ }
+
+ private:
+
+ expression_ptr index_;
+ const bool index_deletable_;
+ vector_holder_ptr vector_holder_;
+ vds_t vds_;
+ };
+
+ template <typename T>
+ class rebasevector_celem_node : public expression_node<T>,
+ public ivariable <T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+ typedef vector_holder<T> vector_holder_t;
+ typedef vector_holder_t* vector_holder_ptr;
+ typedef vec_data_store<T> vds_t;
+
+ rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder)
+ : index_(index),
+ vector_holder_(vec_holder),
+ vds_((*vector_holder_).size(),(*vector_holder_)[0])
+ {
+ vector_holder_->set_ref(&vds_.ref());
+ }
+
+ inline T value() const
+ {
+ return *(vds_.data() + index_);
+ }
+
+ inline T& ref()
+ {
+ return *(vds_.data() + index_);
+ }
+
+ inline const T& ref() const
+ {
+ return *(vds_.data() + index_);
+ }
+
+ inline typename expression_node<T>::node_type type() const
+ {
+ return expression_node<T>::e_rbveccelem;
+ }
+
+ inline vector_holder_t& vec_holder()
+ {
+ return (*vector_holder_);
+ }
+
+ private:
+
+ const std::size_t index_;
+ vector_holder_ptr vector_holder_;
+ vds_t vds_;
+ };
+
+ template <typename T>
+ class vector_assignment_node : public expression_node<T>
+ {
+ public:
+
+ typedef expression_node<T>* expression_ptr;
+
+ vector_assignment_node(T* vector_base,
+ const std::size_t& size,
+ const std::vector<expression_ptr>& initialiser_list,
+ const bool single_value_initialse)
+ : vector_base_(vector_base),
+ initialiser_list_(initialiser_list),
+ size_(size),
+ single_value_initialse_(single_value_initialse)
+ {}
+
+ ~vector_assignment_node()
+ {
+ for (std::size_t i = 0; i < initialiser_list_.size(); ++i)
+ {
+ if (branch_deletable(initialiser_list_[i]))
+ {
+ destroy_node(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;
+&nbs