src/UnityOncoSimul/exprtk.h
4068375e
 /*
  ******************************************************************
  *           C++ Mathematical Expression Toolkit Library          *
  *                                                                *
a65c8e8b
  * Author: Arash Partow (1999-2022)                               *
  * URL: https://www.partow.net/programming/exprtk/index.html      *
4068375e
  *                                                                *
  * 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.                            *
a65c8e8b
  * https://www.opensource.org/licenses/MIT                        *
4068375e
  *                                                                *
  * 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>
a65c8e8b
 #include <cassert>
4068375e
 #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
 
a65c8e8b
    #if __cplusplus >= 201103L
       #define exprtk_override override
       #define exprtk_final    final
       #define exprtk_delete   = delete
    #else
       #define exprtk_override
       #define exprtk_final
       #define exprtk_delete
    #endif
 
4068375e
    namespace details
    {
a65c8e8b
       typedef char                   char_t;
       typedef char_t*                char_ptr;
4068375e
       typedef char_t const*          char_cptr;
a65c8e8b
       typedef unsigned char          uchar_t;
       typedef uchar_t*               uchar_ptr;
       typedef uchar_t const*         uchar_cptr;
4068375e
       typedef unsigned long long int _uint64_t;
a65c8e8b
       typedef long long int          _int64_t;
4068375e
 
       inline bool is_whitespace(const char_t c)
       {
          return (' '  == c) || ('\n' == c) ||
                 ('\r' == c) || ('\t' == c) ||
                 ('\b' == c) || ('\v' == c) ||
                 ('\f' == c) ;
       }
 
       inline bool is_operator_char(const char_t c)
       {
          return ('+' == c) || ('-' == c) ||
                 ('*' == c) || ('/' == c) ||
                 ('^' == c) || ('<' == c) ||
                 ('>' == c) || ('=' == c) ||
                 (',' == c) || ('!' == c) ||
                 ('(' == c) || (')' == c) ||
                 ('[' == c) || (']' == c) ||
                 ('{' == c) || ('}' == c) ||
                 ('%' == c) || (':' == c) ||
                 ('?' == c) || ('&' == c) ||
                 ('|' == c) || (';' == c) ;
       }
 
       inline bool is_letter(const char_t c)
       {
          return (('a' <= c) && (c <= 'z')) ||
                 (('A' <= c) && (c <= 'Z')) ;
       }
 
       inline bool is_digit(const char_t c)
       {
          return ('0' <= c) && (c <= '9');
       }
 
       inline bool is_letter_or_digit(const char_t c)
       {
          return is_letter(c) || is_digit(c);
       }
 
       inline bool is_left_bracket(const char_t c)
       {
          return ('(' == c) || ('[' == c) || ('{' == c);
       }
 
       inline bool is_right_bracket(const char_t c)
       {
          return (')' == c) || (']' == c) || ('}' == c);
       }
 
       inline bool is_bracket(const char_t c)
       {
          return is_left_bracket(c) || is_right_bracket(c);
       }
 
       inline bool is_sign(const char_t c)
       {
          return ('+' == c) || ('-' == c);
       }
 
       inline bool is_invalid(const char_t c)
       {
          return !is_whitespace   (c) &&
                 !is_operator_char(c) &&
                 !is_letter       (c) &&
                 !is_digit        (c) &&
                 ('.'  != c)          &&
                 ('_'  != c)          &&
                 ('$'  != c)          &&
                 ('~'  != c)          &&
                 ('\'' != c);
       }
 
       inline bool is_valid_string_char(const char_t c)
       {
a65c8e8b
          return std::isprint(static_cast<uchar_t>(c)) ||
4068375e
                 is_whitespace(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)
             {
a65c8e8b
                const char_t c1 = static_cast<char_t>(std::tolower(s1[i]));
                const char_t c2 = static_cast<char_t>(std::tolower(s2[i]));
4068375e
 
                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;
 
a65c8e8b
          const int sign = (i < 0) ? -1 : 1;
4068375e
 
a65c8e8b
          for ( ; i; i /= 10)
          {
             result += '0' + static_cast<char_t>(sign * (i % 10));
4068375e
          }
a65c8e8b
 
          if (sign < 0)
4068375e
          {
a65c8e8b
             result += '-';
4068375e
          }
 
          std::reverse(result.begin(), result.end());
 
a65c8e8b
 
4068375e
          return result;
       }
 
       inline std::string to_str(std::size_t i)
       {
          return to_str(static_cast<int>(i));
       }
 
a65c8e8b
       inline bool is_hex_digit(const uchar_t digit)
4068375e
       {
          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
a65c8e8b
             return static_cast<uchar_t>(std::toupper(h) - 'A');
4068375e
       }
 
       template <typename Iterator>
       inline bool parse_hex(Iterator& itr, Iterator end,
a65c8e8b
                             char_t& result)
4068375e
       {
          if (
               (end ==  (itr    ))               ||
               (end ==  (itr + 1))               ||
               (end ==  (itr + 2))               ||
               (end ==  (itr + 3))               ||
               ('0' != *(itr    ))               ||
               ('X' != std::toupper(*(itr + 1))) ||
               (!is_hex_digit(*(itr + 2)))       ||
               (!is_hex_digit(*(itr + 3)))
             )
          {
             return false;
          }
 
          result = hex_to_bin(static_cast<uchar_t>(*(itr + 2))) << 4 |
                   hex_to_bin(static_cast<uchar_t>(*(itr + 3))) ;
 
          return true;
       }
 
       inline bool 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))
             {
                if (end == ++itr1)
                {
                   return false;
                }
                else if (parse_hex(itr1, end, *itr2))
                {
                   itr1+= 4;
                   itr2+= 1;
                   removal_count +=4;
                }
                else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; }
                else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; }
                else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; }
                else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; }
                else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; }
                else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; }
                else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; }
                else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; }
                else
                {
                   (*itr2++) = (*itr1++);
                   ++removal_count;
                }
                continue;
             }
             else
                (*itr2++) = (*itr1++);
          }
 
          if ((removal_count > s.size()) || (0 == removal_count))
             return false;
 
          s.resize(s.size() - removal_count);
 
          return true;
       }
 
       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,
a65c8e8b
                              const typename std::iterator_traits<Iterator>::value_type& exactly_one )
4068375e
       {
          const Iterator null_itr(0);
 
a65c8e8b
          Iterator p_itr  = pattern_begin;
          Iterator d_itr  = data_begin;
          Iterator np_itr = null_itr;
          Iterator nd_itr = null_itr;
4068375e
 
a65c8e8b
          for ( ; ; )
4068375e
          {
a65c8e8b
             const bool pvalid = p_itr != pattern_end;
             const bool dvalid = d_itr != data_end;
4068375e
 
a65c8e8b
             if (!pvalid && !dvalid)
                break;
4068375e
 
a65c8e8b
             if (pvalid)
             {
4068375e
                const typename std::iterator_traits<Iterator>::value_type c = *(p_itr);
 
a65c8e8b
                if (zero_or_more == c)
                {
                   np_itr = p_itr;
                   nd_itr = d_itr + 1;
                   ++p_itr;
                   continue;
                }
                else if (dvalid && ((exactly_one == c) || Compare::cmp(c,*(d_itr))))
4068375e
                {
a65c8e8b
                   ++p_itr;
4068375e
                   ++d_itr;
a65c8e8b
                   continue;
4068375e
                }
             }
 
a65c8e8b
             if ((null_itr != nd_itr) && (nd_itr <= data_end))
             {
                p_itr = np_itr;
                d_itr = nd_itr;
4068375e
                continue;
             }
 
a65c8e8b
             return false;
4068375e
          }
 
a65c8e8b
          return true;
4068375e
       }
 
       inline bool wc_match(const std::string& wild_card,
                            const std::string& str)
       {
a65c8e8b
          return match_impl<char_cptr,cs_match>(
                    wild_card.data(),
                    wild_card.data() + wild_card.size(),
                    str.data(),
                    str.data() + str.size(),
                    '*', '?');
4068375e
       }
 
       inline bool wc_imatch(const std::string& wild_card,
                             const std::string& str)
       {
a65c8e8b
          return match_impl<char_cptr,cis_match>(
                    wild_card.data(),
                    wild_card.data() + wild_card.size(),
                    str.data(),
                    str.data() + str.size(),
                    '*', '?');
4068375e
       }
 
       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();
 
a65c8e8b
          const itr_t p_end = pattern.end();
          const itr_t s_end = str    .end();
4068375e
 
          while ((s_end != s_itr) && (p_end != p_itr))
          {
             if ('*' == (*p_itr))
             {
a65c8e8b
                const char_t target = static_cast<char_t>(std::toupper(*(p_itr - 1)));
4068375e
 
                if ('*' == target)
                {
                   diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr));
a65c8e8b
                   diff_value = static_cast<char_t>(std::toupper(*p_itr));
4068375e
 
                   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));
a65c8e8b
                diff_value = static_cast<char_t>(std::toupper(*p_itr));
4068375e
 
                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)             \
a65c8e8b
             template <> struct number_type<T>                    \
4068375e
             { typedef real_type_tag type; number_type() {} };    \
 
             #define exprtk_register_complex_type_tag(T)          \
a65c8e8b
             template <> struct number_type<std::complex<T> >     \
4068375e
             { typedef complex_type_tag type; number_type() {} }; \
 
             #define exprtk_register_int_type_tag(T)              \
a65c8e8b
             template <> struct number_type<T>                    \
4068375e
             { 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>
a65c8e8b
             struct epsilon_type {};
4068375e
 
a65c8e8b
             #define exprtk_define_epsilon_type(Type, Epsilon)      \
             template <> struct epsilon_type<Type>                  \
             {                                                      \
                static inline Type value()                          \
                {                                                   \
                   const Type epsilon = static_cast<Type>(Epsilon); \
                   return epsilon;                                  \
                }                                                   \
             };                                                     \
4068375e
 
a65c8e8b
             exprtk_define_epsilon_type(float      , 0.00000100000f)
             exprtk_define_epsilon_type(double     , 0.000000000100)
             exprtk_define_epsilon_type(long double, 0.000000000001)
 
             #undef exprtk_define_epsilon_type
4068375e
 
             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)
             {
a65c8e8b
                const int index = std::max<int>(0, std::min<int>(pow10_size - 1, static_cast<int>(std::floor(v1))));
4068375e
                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)
             {
a65c8e8b
                if      (v > T(0)) return T(+1);
4068375e
                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)
             {
a65c8e8b
                if      (v > T(0)) return T(+1);
4068375e
                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)
a65c8e8b
             #define exprtk_define_erf(TT, impl)                \
             inline TT erf_impl(const TT v) { return impl(v); } \
4068375e
 
             exprtk_define_erf(      float,::erff)
             exprtk_define_erf(     double,::erf )
             exprtk_define_erf(long double,::erfl)
             #undef exprtk_define_erf
             #endif
 
             template <typename T>
a65c8e8b
             inline T erf_impl(const T v, real_type_tag)
4068375e
             {
                #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()));
 
a65c8e8b
                const 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]))))))))));
4068375e
 
                return (v >= T(0)) ? result : -result;
                #else
                return erf_impl(v);
                #endif
             }
 
             template <typename T>
a65c8e8b
             inline T erf_impl(const T v, int_type_tag)
4068375e
             {
                return erf_impl(static_cast<double>(v),real_type_tag());
             }
 
             #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER)
a65c8e8b
             #define exprtk_define_erfc(TT, impl)                \
             inline TT erfc_impl(const TT v) { return impl(v); } \
4068375e
 
a65c8e8b
             exprtk_define_erfc(float      ,::erfcf)
             exprtk_define_erfc(double     ,::erfc )
4068375e
             exprtk_define_erfc(long double,::erfcl)
             #undef exprtk_define_erfc
             #endif
 
             template <typename T>
a65c8e8b
             inline T erfc_impl(const T v, real_type_tag)
4068375e
             {
                #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>
a65c8e8b
             inline T erfc_impl(const T v, int_type_tag)
4068375e
             {
                return erfc_impl(static_cast<double>(v),real_type_tag());
             }
 
             template <typename T>
a65c8e8b
             inline T ncdf_impl(const T v, real_type_tag)
4068375e
             {
a65c8e8b
                const T cnd = T(0.5) * (T(1) +
                              erf_impl(abs_impl(v,real_type_tag()) /
                                       T(numeric::constant::sqrt2),real_type_tag()));
4068375e
                return  (v < T(0)) ? (T(1) - cnd) : cnd;
             }
 
             template <typename T>
a65c8e8b
             inline T ncdf_impl(const T v, int_type_tag)
4068375e
             {
                return ncdf_impl(static_cast<double>(v),real_type_tag());
             }
 
             template <typename T>
a65c8e8b
             inline T sinc_impl(const T v, real_type_tag)
4068375e
             {
                if (std::abs(v) >= std::numeric_limits<T>::epsilon())
                    return(std::sin(v) / v);
                else
                   return T(1);
             }
 
             template <typename T>
a65c8e8b
             inline T sinc_impl(const T v, int_type_tag)
4068375e
             {
                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));  }
a65c8e8b
             template <typename T> inline T   d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); }
             template <typename T> inline T   g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); }
4068375e
             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));    }
 
a65c8e8b
             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 const_qnan_impl(real_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
4068375e
 
             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 }; };
 
a65c8e8b
          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 }; };
4068375e
 
          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)
                {
a65c8e8b
                   if (1 == (k % 2))
4068375e
                   {
                      l *= v;
                      --k;
                   }
 
                   v *= v;
a65c8e8b
                   k /= 2;
4068375e
                }
 
                return l;
             }
          };
 
a65c8e8b
          template <typename T> struct fast_exp<T,10> { static inline T result(const 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(const T v) { return fast_exp<T,8>::result(v) * v; } };
          template <typename T> struct fast_exp<T, 8> { static inline T result(const 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(const T v) { return fast_exp<T,6>::result(v) * v; } };
          template <typename T> struct fast_exp<T, 6> { static inline T result(const 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(const T v) { return fast_exp<T,4>::result(v) * v; } };
          template <typename T> struct fast_exp<T, 4> { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } };
          template <typename T> struct fast_exp<T, 3> { static inline T result(const T v) { return v * v * v; } };
          template <typename T> struct fast_exp<T, 2> { static inline T result(const T v) { return v * v;     } };
          template <typename T> struct fast_exp<T, 1> { static inline T result(const T v) { return v;         } };
          template <typename T> struct fast_exp<T, 0> { static inline T result(const T  ) { return T(1);      } };
4068375e
 
          #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;
a65c8e8b
          const std::size_t length = static_cast<std::size_t>(std::distance(itr,end));
4068375e
 
          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
 
a65c8e8b
                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;
                         }
4068375e
 
                #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>
a65c8e8b
       static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative)
4068375e
       {
          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)
          {
a65c8e8b
             if (*inf_itr == static_cast<char_t>(*itr))
4068375e
             {
                ++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 T>
       inline bool valid_exponent(const int exponent, numeric::details::real_type_tag)
       {
a65c8e8b
          using namespace details::numeric;
          return (numeric_info<T>::min_exp <= exponent) && (exponent <= numeric_info<T>::max_exp);
4068375e
       }
 
       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; }     \
a65c8e8b
          else                              \
             { break; }                     \
4068375e
             ++itr;                         \
 
          if ('.' != (*itr))
          {
             const Iterator curr = itr;
 
             while ((end != itr) && (zero == (*itr))) ++itr;
 
             while (end != itr)
             {
                unsigned int digit;
                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;
                T tmp_d = T(0);
 
                while (end != itr)
                {
                   unsigned int digit;
                   parse_digit_1(tmp_d)
                   parse_digit_1(tmp_d)
                   parse_digit_2(tmp_d)
                }
 
                if (curr != itr)
                {
                   instate = true;
 
a65c8e8b
                   const int frac_exponent = static_cast<int>(-std::distance(curr, itr));
4068375e
 
a65c8e8b
                   if (!valid_exponent<T>(frac_exponent, numeric::details::real_type_tag()))
4068375e
                      return false;
 
a65c8e8b
                   d += compute_pow10(tmp_d, frac_exponent);
4068375e
                }
 
                #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 (!valid_exponent<T>(exponent, numeric::details::real_type_tag()))
             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
 
    struct loop_runtime_check
    {
       enum loop_types
       {
          e_invalid           = 0,
          e_for_loop          = 1,
          e_while_loop        = 2,
          e_repeat_until_loop = 4,
          e_all_loops         = 7
       };
 
       enum violation_type
       {
           e_unknown         = 0,
           e_iteration_count = 1,
           e_timeout         = 2
       };
 
       loop_types loop_set;
 
       loop_runtime_check()
a65c8e8b
       : loop_set(e_invalid)
       , max_loop_iterations(0)
4068375e
       {}
 
       details::_uint64_t max_loop_iterations;
 
       struct violation_context
       {
          loop_types loop;
          violation_type violation;
          details::_uint64_t iteration_count;
       };
 
       virtual void handle_runtime_violation(const violation_context&)
       {
          throw std::runtime_error("ExprTk Loop run-time violation.");
       }
 
       virtual ~loop_runtime_check() {}
    };
 
    typedef loop_runtime_check* loop_runtime_check_ptr;
 
    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()
a65c8e8b
          : type(e_none)
          , value("")
          , position(std::numeric_limits<std::size_t>::max())
4068375e
          {}
 
          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 token_list_t::iterator token_list_itr_t;
          typedef details::char_t char_t;
 
          generator()
a65c8e8b
          : base_itr_(0)
          , s_itr_   (0)
          , s_end_   (0)
4068375e
          {
             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);
             }
          }
 
a65c8e8b
          inline std::string substr(const std::size_t& begin, const std::size_t& end) const
4068375e
          {
             const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
a65c8e8b
             const details::char_cptr end_itr   = ((base_itr_ + end  ) < s_end_) ? (base_itr_ + end  ) : s_end_;
4068375e
 
             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:
 
a65c8e8b
          inline bool is_end(details::char_cptr itr) const
4068375e
          {
             return (s_end_ == itr);
          }
 
a65c8e8b
          #ifndef exprtk_disable_comments
          inline bool is_comment_start(details::char_cptr itr) const
4068375e
          {
             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;
             }
             return false;
          }
a65c8e8b
          #else
          inline bool is_comment_start(details::char_cptr) const
          {
             return false;
          }
          #endif
4068375e
 
          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;
a65c8e8b
                   if      ('#' == c0)    { mode = 1; incr = 1; }
4068375e
                   else if ('/' == c0)
                   {
a65c8e8b
                      if      ('/' == c1) { mode = 1; incr = 2; }
4068375e
                      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;
 
a65c8e8b
                if      ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte;
4068375e
                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)
             {
a65c8e8b
                t.set_error(
                   token::e_err_sfunc,
                   initial_itr, std::min(initial_itr + 11, s_end_),
                   base_itr_);
4068375e
                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))))
                )
             {
a65c8e8b
                t.set_error(
                   token::e_err_sfunc,
                   initial_itr, std::min(initial_itr + 4, s_end_),
                   base_itr_);
4068375e
                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 (!details::is_valid_string_char(*s_itr_))
                {
                   t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
                   token_list_.push_back(t);
 
                   return;
                }
                else 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_)) &&
                        ((s_itr_ + 4) <= s_end_)
                      )
                   {
                      const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1)));
 
                      const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) &&
                                               details::is_hex_digit(*(s_itr_ + 3)) ;
 
                      if (!(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_);
 
                if (!details::cleanup_escapes(parsed_string))
                {
                   t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
                   token_list_.push_back(t);
 
                   return;
                }
 
                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;
a65c8e8b
       }; // class generator
4068375e
 
       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:
 
a65c8e8b
          virtual ~token_scanner() {}
4068375e
 
          explicit token_scanner(const std::size_t& stride)
          : stride_(stride)
          {
             if (stride > 4)
             {
                throw std::invalid_argument("token_scanner() - Invalid stride value");
             }
          }
 
a65c8e8b
          inline std::size_t process(generator& g) exprtk_override
4068375e
          {
             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_;
a65c8e8b
       }; // class token_scanner
4068375e
 
       class token_modifier : public helper_interface
       {
       public:
 
a65c8e8b
          inline std::size_t process(generator& g) exprtk_override
4068375e
          {
             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");
             }
          }
 
a65c8e8b
          inline std::size_t process(generator& g) exprtk_override
4068375e
          {
             if (g.token_list_.empty())
                return 0;
             else if (g.token_list_.size() < stride_)
                return 0;
 
             std::size_t changes = 0;
 
             typedef std::pair<std::size_t, token> insert_t;
             std::vector<insert_t> insert_list;
             insert_list.reserve(10000);
 
             for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
             {
                int insert_index = -1;
                token t;
 
                switch (stride_)
                {
                   case 1 : insert_index = insert(g.token_list_[i],t);
                            break;
 
                   case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t);
                            break;
 
                   case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t);
                            break;
 
                   case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t);
                            break;
 
                   case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t);
                            break;
                }
 
                if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1)))
                {
                   insert_list.push_back(insert_t(i, t));
                   changes++;
                }
             }
 
             if (!insert_list.empty())
             {
                generator::token_list_t token_list;
 
                std::size_t insert_index = 0;
 
                for (std::size_t i = 0; i < g.token_list_.size(); ++i)
                {
                   token_list.push_back(g.token_list_[i]);
 
                   if (
                        (insert_index < insert_list.size()) &&
                        (insert_list[insert_index].first == i)
                      )
                   {
                      token_list.push_back(insert_list[insert_index].second);
                      insert_index++;
                   }
                }
 
                std::swap(g.token_list_,token_list);
             }
 
             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)
          {}
 
a65c8e8b
          inline std::size_t process(generator& g) exprtk_override
4068375e
          {
             if (g.token_list_.empty())
                return 0;
 
             switch (stride_)
             {
                case 2  : return process_stride_2(g);
                case 3  : return process_stride_3(g);
                default : return 0;
             }
          }
 
          virtual bool join(const token&, const token&, token&)               { return false; }
          virtual bool join(const token&, const token&, const token&, token&) { return false; }
 
       private:
 
          inline std::size_t process_stride_2(generator& g)
          {
             if (g.token_list_.size() < 2)
                return 0;
 
             std::size_t changes = 0;
 
             generator::token_list_t token_list;
             token_list.reserve(10000);
 
             for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 1); ++i)
             {
                token t;
 
                for ( ; ; )
                {
                   if (!join(g[i], g[i + 1], t))
                   {
                      token_list.push_back(g[i]);
                      break;
                   }
 
                   token_list.push_back(t);
 
                   ++changes;
 
                   i+=2;
 
a65c8e8b
                   if (static_cast<std::size_t>(i) >= (g.token_list_.size() - 1))
4068375e
                      break;
                }
             }
 
             token_list.push_back(g.token_list_.back());
 
a65c8e8b
             assert(token_list.size() <= g.token_list_.size());
 
4068375e
             std::swap(token_list, g.token_list_);
 
             return changes;
          }
 
          inline std::size_t process_stride_3(generator& g)
          {
             if (g.token_list_.size() < 3)
                return 0;
 
             std::size_t changes = 0;
 
             generator::token_list_t token_list;
             token_list.reserve(10000);
 
             for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 2); ++i)
             {
                token t;
 
                for ( ; ; )
                {
                   if (!join(g[i], g[i + 1], g[i + 2], t))
                   {
                      token_list.push_back(g[i]);
                      break;
                   }
 
                   token_list.push_back(t);
 
                   ++changes;
 
                   i+=3;
 
a65c8e8b
                   if (static_cast<std::size_t>(i) >= (g.token_list_.size() - 2))
4068375e
                      break;
                }
             }
 
             token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2));
             token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1));
 
a65c8e8b
             assert(token_list.size() <= g.token_list_.size());
 
4068375e
             std::swap(token_list, g.token_list_);
 
             return changes;
          }
 
          const std::size_t stride_;
       };
 
       namespace helper
       {
 
          inline void dump(const lexer::generator& generator)
          {
             for (std::size_t i = 0; i < generator.size(); ++i)
             {
                const 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;
                   }
                }
a65c8e8b
                if      ((t0.type == lexer::token::e_number     ) && (t1.type == lexer::token::e_symbol     )) match = true;
4068375e
                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;
                }
                // '! =' --> '!='
a65c8e8b
                else if ((static_cast<details::char_t>(t0.type) == '!') && (t1.type == lexer::token::e_eq))
4068375e
                {
                   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;
             }
 
a65c8e8b
             inline bool join(const lexer::token& t0,
                              const lexer::token& t1,
                              const lexer::token& t2,
                              lexer::token& t)
4068375e
             {
                // '[ * ]' --> '[*]'
                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()
a65c8e8b
             : token_scanner(1)
             , state_(true)
4068375e
             {}
 
             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];
 
a65c8e8b
                   if      (t.type == lexer::token::e_lbracket   ) stack_.push(std::make_pair(')',t.position));
4068375e
                   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()
a65c8e8b
             : token_scanner (1)
             , current_index_(0)
4068375e
             {}
 
             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:
 
a65c8e8b
             void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t)
4068375e
             {
                invalid_comb_.insert(std::make_pair(base,t));
             }
 
a65c8e8b
             void add_invalid_set1(const lexer::token::token_type t)
4068375e
             {
                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 );
             }
 
a65c8e8b
             bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t)
4068375e
             {
a65c8e8b
                if (details::is_right_bracket(static_cast<details::char_t>(base)))
4068375e
                {
                   switch (t)
                   {
                      case lexer::token::e_assign : return (']' != base);
                      case lexer::token::e_string : return (')' != base);
                      default                     : return false;
                   }
                }
a65c8e8b
                else if (details::is_left_bracket(static_cast<details::char_t>(base)))
4068375e
                {
a65c8e8b
                   if (details::is_right_bracket(static_cast<details::char_t>(t)))
4068375e
                      return false;
a65c8e8b
                   else if (details::is_left_bracket(static_cast<details::char_t>(t)))
4068375e
                      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 ;
                      }
                   }
                }
a65c8e8b
                else if (details::is_right_bracket(static_cast<details::char_t>(t)))
4068375e
                {
                   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 ;
                   }
                }
a65c8e8b
                else if (details::is_left_bracket(static_cast<details::char_t>(t)))
4068375e
                {
                   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)
             {
a65c8e8b
                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 );
4068375e
 
a65c8e8b
                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   );
4068375e
 
a65c8e8b
                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   );
4068375e
             }
 
             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:
 
a65c8e8b
             void add_invalid(const token_t t0, const token_t t1, const token_t t2)
4068375e
             {
                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:
 
a65c8e8b
          typedef token     token_t;
4068375e
          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)
a65c8e8b
       : size_(size)
       , data_(data)
       , data_ref_(0)
4068375e
       {}
 
       vector_view(const vector_view<T>& vv)
a65c8e8b
       : size_(vv.size_)
       , data_(vv.data_)
       , data_ref_(0)
4068375e
       {}
 
       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()
a65c8e8b
       : data(0)
       , size(0)
       , type(e_unknown)
4068375e
       {}
 
       union
       {
a65c8e8b
          void* data;
          T*    vec_data;
4068375e
       };
 
       std::size_t size;
       store_type  type;
 
       class parameter_list
       {
       public:
 
a65c8e8b
          explicit parameter_list(std::vector<type_store>& pl)
4068375e
          : 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;
 
a65c8e8b
          explicit type_view(type_store_t& ts)
          : ts_(ts)
          , data_(reinterpret_cast<value_t*>(ts_.data))
4068375e
          {}
 
a65c8e8b
          explicit type_view(const type_store_t& ts)
          : ts_(const_cast<type_store_t&>(ts))
          , data_(reinterpret_cast<value_t*>(ts_.data))
4068375e
          {}
 
          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;
 
a65c8e8b
          explicit scalar_view(type_store_t& ts)
4068375e
          : v_(*reinterpret_cast<value_t*>(ts.data))
          {}
 
a65c8e8b
          explicit scalar_view(const type_store_t& ts)
4068375e
          : 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)
a65c8e8b
          : type(t)
          , num_params(np)
4068375e
          {}
 
          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
          {
             explicit details(const std::size_t& vsize,
                              const unsigned int loop_batch_size = global_loop_batch_size)
a65c8e8b
             : batch_size(loop_batch_size   )
             , remainder (vsize % batch_size)
             , upper_bound(static_cast<int>(vsize - (remainder ? loop_batch_size : 0)))
4068375e
             {}
 
             unsigned int batch_size;
a65c8e8b
             int remainder;
4068375e
             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()
a65c8e8b
             : ref_count(1)
             , size     (0)
             , data     (0)
             , destruct (true)
4068375e
             {}
 
a65c8e8b
             explicit control_block(const std::size_t& dsize)
             : ref_count(1    )
             , size     (dsize)
             , data     (0    )
             , destruct (true )
4068375e
             { create_data(); }
 
             control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false)
a65c8e8b
             : ref_count(1     )
             , size     (dsize )
             , data     (dptr  )
             , destruct (dstrct)
4068375e
             {}
 
            ~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:
 
a65c8e8b
             control_block(const control_block&) exprtk_delete;
             control_block& operator=(const control_block&) exprtk_delete;
4068375e
 
             inline void create_data()
             {
                destruct = true;
                data     = new T[size];
a65c8e8b
                std::fill_n(data, size, T(0));
                dump_ptr("control_block::create_data() - data", data, size);
4068375e
             }
          };
 
       public:
 
          vec_data_store()
          : control_block_(control_block::create(0))
          {}
 
a65c8e8b
          explicit vec_data_store(const std::size_t& size)
          : control_block_(control_block::create(size,reinterpret_cast<data_t>(0),true))
4068375e
          {}
 
          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() 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)
          {
             const std::size_t size = min_size(vds0.control_block_,vds1.control_block_);
             vds0.control_block_->size = size;
             vds1.control_block_->size = size;
          }
 
       private:
 
a65c8e8b
          static inline std::size_t min_size(const control_block* cb0, const control_block* cb1)
4068375e
          {
             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 Node>
       struct node_collector_interface
       {
          typedef Node* node_ptr_t;
          typedef Node** node_pp_t;
          typedef std::vector<node_pp_t> noderef_list_t;
 
          virtual ~node_collector_interface() {}
 
          virtual void collect_nodes(noderef_list_t&) {}
       };
 
       template <typename Node>
       struct node_depth_base;
 
       template <typename T>
       class expression_node : public node_collector_interface<expression_node<T> >,
                               public node_depth_base<expression_node<T> >
       {
       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  ,
a65c8e8b
             e_valvecarith   , e_vecunaryop    , e_vecondition , e_break        ,
             e_continue      , e_swap
4068375e
          };
 
          typedef T value_type;
          typedef expression_node<T>* expression_ptr;
          typedef node_collector_interface<expression_node<T> > nci_t;
          typedef typename nci_t::noderef_list_t noderef_list_t;
          typedef node_depth_base<expression_node<T> > ndb_t;
 
a65c8e8b
          virtual ~expression_node() {}
4068375e
 
          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;
          }
a65c8e8b
       }; // class expression_node
4068375e
 
       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());
       }
 
a65c8e8b
       template <typename T>
       inline bool is_true(const std::pair<expression_node<T>*,bool>& node)
       {
          return std::not_equal_to<T>()(T(0),node.first->value());
       }
 
4068375e
       template <typename T>
       inline bool is_false(const expression_node<T>* node)
       {
          return std::equal_to<T>()(T(0),node->value());
       }
 
a65c8e8b
       template <typename T>
       inline bool is_false(const std::pair<expression_node<T>*,bool>& node)
       {
          return std::equal_to<T>()(T(0),node.first->value());
       }
 
4068375e
       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 :
a65c8e8b
                case details::expression_node<T>::e_vecunaryop  :
                case details::expression_node<T>::e_vecondition : return true;
4068375e
                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 (0 != node)             &&
                 !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 Node>
       class node_collection_destructor
       {
       public:
 
          typedef node_collector_interface<Node> nci_t;
 
          typedef typename nci_t::node_ptr_t     node_ptr_t;
          typedef typename nci_t::node_pp_t      node_pp_t;
          typedef typename nci_t::noderef_list_t noderef_list_t;
 
          static void delete_nodes(node_ptr_t& root)
          {
             std::vector<node_pp_t> node_delete_list;
             node_delete_list.reserve(1000);
 
             collect_nodes(root, node_delete_list);
 
             for (std::size_t i = 0; i < node_delete_list.size(); ++i)
             {
                node_ptr_t& node = *node_delete_list[i];
                exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", static_cast<void*>(node)));
                delete node;
                node = reinterpret_cast<node_ptr_t>(0);
             }
          }
 
       private:
 
          static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list)
          {
             std::deque<node_ptr_t> node_list;
             node_list.push_back(root);
             node_delete_list.push_back(&root);
 
             noderef_list_t child_node_delete_list;
             child_node_delete_list.reserve(1000);
 
             while (!node_list.empty())
             {
                node_list.front()->collect_nodes(child_node_delete_list);
 
                if (!child_node_delete_list.empty())
                {
                   for (std::size_t i = 0; i < child_node_delete_list.size(); ++i)
                   {
                      node_pp_t& node = child_node_delete_list[i];
 
                      if (0 == (*node))
                      {
                         exprtk_debug(("ncd::collect_nodes() - null node encountered.\n"));
                      }
 
                      node_list.push_back(*node);
                   }
 
                   node_delete_list.insert(
                      node_delete_list.end(),
                      child_node_delete_list.begin(), child_node_delete_list.end());
 
                   child_node_delete_list.clear();
                }
 
                node_list.pop_front();
             }
 
             std::reverse(node_delete_list.begin(), node_delete_list.end());
          }
       };
 
       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&, expression_node<T>*& node)
       {
          if ((0 == node) || is_variable_node(node) || is_string_node(node))
          {
             return;
          }
 
          node_collection_destructor<expression_node<T> >
             ::delete_nodes(node);
       }
 
       template <typename T>
       inline void destroy_node(expression_node<T>*& node)
       {
          if (0 != node)
          {
             node_collection_destructor<expression_node<T> >
                ::delete_nodes(node);
          }
       }
 
       template <typename Node>
       struct node_depth_base
       {
a65c8e8b
          typedef Node* node_ptr_t;
          typedef std::pair<node_ptr_t,bool> nb_pair_t;
 
4068375e
          node_depth_base()
a65c8e8b
          : depth_set(false)
          , depth(0)
4068375e
          {}
 
          virtual ~node_depth_base() {}
 
          virtual std::size_t node_depth() const { return 1; }
 
          std::size_t compute_node_depth(const Node* const& node) const
          {
             if (!depth_set)
             {
                depth = 1 + (node ? node->node_depth() : 0);
                depth_set = true;
             }
 
             return depth;
          }
 
a65c8e8b
          std::size_t compute_node_depth(const nb_pair_t& branch) const
4068375e
          {
             if (!depth_set)
             {
                depth = 1 + (branch.first ? branch.first->node_depth() : 0);
                depth_set = true;
             }
 
             return depth;
          }
 
          template <std::size_t N>
a65c8e8b
          std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const
4068375e
          {
             if (!depth_set)
             {
                depth = 0;
                for (std::size_t i = 0; i < N; ++i)
                {
                   if (branch[i].first)
                   {
                      depth = std::max(depth,branch[i].first->node_depth());
                   }
                }
                depth += 1;
                depth_set = true;
             }
 
             return depth;
          }
 
          template <typename BranchType>
          std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const
          {
             if (!depth_set)
             {
                depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1));
                depth_set = true;
             }
 
             return depth;
          }
 
          template <typename BranchType>
          std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1,
                                         const BranchType& n2) const
          {
             if (!depth_set)
             {
                depth = 1 + std::max(
                               std::max(compute_node_depth(n0), compute_node_depth(n1)),
                               compute_node_depth(n2));
                depth_set = true;
             }
 
             return depth;
          }
 
          template <typename BranchType>
          std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1,
                                         const BranchType& n2, const BranchType& n3) const
          {
             if (!depth_set)
             {
                depth = 1 + std::max(
                            std::max(compute_node_depth(n0), compute_node_depth(n1)),
                            std::max(compute_node_depth(n2), compute_node_depth(n3)));
                depth_set = true;
             }
 
             return depth;
          }
 
          template <typename Allocator,
                    template <typename, typename> class Sequence>
a65c8e8b
          std::size_t compute_node_depth(const Sequence<node_ptr_t, Allocator>& branch_list) const
4068375e
          {
             if (!depth_set)
             {
                for (std::size_t i = 0; i < branch_list.size(); ++i)
                {
                   if (branch_list[i])
                   {
                      depth = std::max(depth, compute_node_depth(branch_list[i]));
                   }
                }
                depth_set = true;
             }
 
             return depth;
          }
 
          template <typename Allocator,
                    template <typename, typename> class Sequence>
a65c8e8b
          std::size_t compute_node_depth(const Sequence<nb_pair_t,Allocator>& branch_list) const
4068375e
          {
             if (!depth_set)
             {
                for (std::size_t i = 0; i < branch_list.size(); ++i)
                {
                   if (branch_list[i].first)
                   {
                      depth = std::max(depth, compute_node_depth(branch_list[i].first));
                   }
                }
                depth_set = true;
             }
 
             return depth;
          }
 
          mutable bool depth_set;
          mutable std::size_t depth;
 
          template <typename NodeSequence>
a65c8e8b
          void collect(node_ptr_t const& node,
4068375e
                       const bool deletable,
                       NodeSequence& delete_node_list) const
          {
             if ((0 != node) && deletable)
             {
a65c8e8b
                delete_node_list.push_back(const_cast<node_ptr_t*>(&node));
4068375e
             }
          }
 
          template <typename NodeSequence>
a65c8e8b
          void collect(const nb_pair_t& branch,
4068375e
                       NodeSequence& delete_node_list) const
          {
             collect(branch.first, branch.second, delete_node_list);
          }
 
          template <typename NodeSequence>
          void collect(Node*& node,
                       NodeSequence& delete_node_list) const
          {
             collect(node, branch_deletable(node), delete_node_list);
          }
 
          template <std::size_t N, typename NodeSequence>
a65c8e8b
          void collect(const nb_pair_t(&branch)[N],
4068375e
                       NodeSequence& delete_node_list) const
          {
             for (std::size_t i = 0; i < N; ++i)
             {
                collect(branch[i].first, branch[i].second, delete_node_list);
             }
          }
 
          template <typename Allocator,
                    template <typename, typename> class Sequence,
                    typename NodeSequence>
a65c8e8b
          void collect(const Sequence<nb_pair_t, Allocator>& branch,
4068375e
                       NodeSequence& delete_node_list) const
          {
             for (std::size_t i = 0; i < branch.size(); ++i)
             {
                collect(branch[i].first, branch[i].second, delete_node_list);
             }
          }
 
          template <typename Allocator,
                    template <typename, typename> class Sequence,
                    typename NodeSequence>
a65c8e8b
          void collect(const Sequence<node_ptr_t, Allocator>& branch_list,
4068375e
                       NodeSequence& delete_node_list) const
          {
             for (std::size_t i = 0; i < branch_list.size(); ++i)
             {
                collect(branch_list[i], branch_deletable(branch_list[i]), delete_node_list);
             }
          }
 
          template <typename Boolean,
                    typename AllocatorT,
                    typename AllocatorB,
                    template <typename, typename> class Sequence,
                    typename NodeSequence>
a65c8e8b
          void collect(const Sequence<node_ptr_t, AllocatorT>& branch_list,
4068375e
                       const Sequence<Boolean, AllocatorB>& branch_deletable_list,
                       NodeSequence& delete_node_list) const
          {
             for (std::size_t i = 0; i < branch_list.size(); ++i)
             {
                collect(branch_list[i], branch_deletable_list[i], delete_node_list);
             }
          }
       };
 
       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)
a65c8e8b
             : vec_(vec)
             , size_(vec_size)
4068375e
             {}
 
          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:
 
a65c8e8b
             array_vector_impl(const array_vector_impl&) exprtk_delete;
             array_vector_impl& operator=(const array_vector_impl&) exprtk_delete;
4068375e
 
             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:
 
a65c8e8b
             sequence_vector_impl(const sequence_vector_impl&) exprtk_delete;
             sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete;
4068375e
 
             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:
 
a65c8e8b
             vector_view_impl(const vector_view_impl&) exprtk_delete;
             vector_view_impl& operator=(const vector_view_impl&) exprtk_delete;
4068375e
 
             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>
a65c8e8b
       class null_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_null;
          }
       };
 
       template <typename T, std::size_t N>
       inline void construct_branch_pair(std::pair<expression_node<T>*,bool> (&branch)[N],
                                         expression_node<T>* b,
                                         const std::size_t& index)
       {
          if (b && (index < N))
          {
             branch[index] = std::make_pair(b,branch_deletable(b));
          }
       }
 
       template <typename T>
       inline void construct_branch_pair(std::pair<expression_node<T>*,bool>& branch, expression_node<T>* b)
       {
          if (b)
          {
             branch = 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(branch, b0, 0);
          construct_branch_pair(branch, b1, 1);
          construct_branch_pair(branch, b2, 2);
          construct_branch_pair(branch, b3, 3);
          construct_branch_pair(branch, b4, 4);
          construct_branch_pair(branch, b5, 5);
          construct_branch_pair(branch, b6, 6);
          construct_branch_pair(branch, b7, 7);
          construct_branch_pair(branch, b8, 8);
          construct_branch_pair(branch, b9, 9);
       }
 
       template <typename T>
a65c8e8b
       class null_eq_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
a65c8e8b
          explicit null_eq_node(expression_ptr branch, const bool equality = true)
4068375e
          : equality_(equality)
          {
a65c8e8b
             construct_branch_pair(branch_, branch);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
 
4068375e
             const T v = branch_.first->value();
             const bool result = details::numeric::is_nan(v);
 
             if (result)
                return (equality_) ? T(1) : T(0);
             else
                return (equality_) ? T(0) : T(1);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_nulleq;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
          bool equality_;
          branch_t branch_;
       };
 
       template <typename T>
a65c8e8b
       class literal_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          explicit literal_node(const T& v)
          : value_(v)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_constant;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return reinterpret_cast<expression_node<T>*>(0);
          }
 
       private:
 
a65c8e8b
          literal_node(const literal_node<T>&) exprtk_delete;
          literal_node<T>& operator=(const literal_node<T>&) exprtk_delete;
4068375e
 
          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;
 
a65c8e8b
          virtual ~range_interface() {}
4068375e
 
          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;
 
a65c8e8b
          virtual ~string_base_node() {}
4068375e
 
          virtual std::string str () const = 0;
 
          virtual char_cptr   base() const = 0;
 
          virtual std::size_t size() const = 0;
       };
 
       template <typename T>
a65c8e8b
       class string_literal_node exprtk_final
                                 : public expression_node <T>,
4068375e
                                   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;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringconst;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return reinterpret_cast<expression_node<T>*>(0);
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return value_.data();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return value_.size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return rp_;
          }
 
       private:
 
a65c8e8b
          string_literal_node(const string_literal_node<T>&) exprtk_delete;
          string_literal_node<T>& operator=(const string_literal_node<T>&) exprtk_delete;
4068375e
 
          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;
          typedef std::pair<expression_ptr,bool> branch_t;
 
a65c8e8b
          unary_node(const operator_type& opr, expression_ptr branch)
4068375e
          : operation_(opr)
          {
a65c8e8b
             construct_branch_pair(branch_,branch);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
 
4068375e
             const T arg = branch_.first->value();
 
             return numeric::process<T>(operation_,arg);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_unary;
          }
 
a65c8e8b
          inline operator_type operation()
4068375e
          {
             return operation_;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
          inline void release()
          {
             branch_.second = false;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       protected:
 
          operator_type operation_;
          branch_t branch_;
       };
 
       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);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_[0].first);
             assert(branch_[1].first);
 
4068375e
             const T arg0 = branch_[0].first->value();
             const T arg1 = branch_[1].first->value();
 
             return numeric::process<T>(operation_,arg0,arg1);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_binary;
          }
 
          inline operator_type operation()
          {
             return operation_;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t& index = 0) const exprtk_override
4068375e
          {
             if (0 == index)
                return branch_[0].first;
             else if (1 == index)
                return branch_[1].first;
             else
                return reinterpret_cast<expression_ptr>(0);
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::template compute_node_depth<2>(branch_);
          }
 
       protected:
 
          operator_type operation_;
          branch_t branch_[2];
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class binary_ext_node exprtk_final : public expression_node<T>
4068375e
       {
       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);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_[0].first);
             assert(branch_[1].first);
 
4068375e
             const T arg0 = branch_[0].first->value();
             const T arg1 = branch_[1].first->value();
 
             return Operation::process(arg0,arg1);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_binary_ext;
          }
 
          inline operator_type operation()
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t& index = 0) const exprtk_override
4068375e
          {
             if (0 == index)
                return branch_[0].first;
             else if (1 == index)
                return branch_[1].first;
             else
                return reinterpret_cast<expression_ptr>(0);
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::template compute_node_depth<2>(branch_);
          }
 
       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);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_[0].first);
             assert(branch_[1].first);
             assert(branch_[2].first);
 
4068375e
             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();
             }
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_trinary;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::template compute_node_depth<3>(branch_);
          }
 
       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);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_quaternary;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::template compute_node_depth<4>(branch_);
          }
 
       protected:
 
          operator_type operation_;
          branch_t branch_[4];
       };
 
       template <typename T>
a65c8e8b
       class conditional_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
a65c8e8b
          conditional_node(expression_ptr condition,
4068375e
                           expression_ptr consequent,
                           expression_ptr alternative)
          {
a65c8e8b
             construct_branch_pair(condition_  , condition  );
4068375e
             construct_branch_pair(consequent_ , consequent );
             construct_branch_pair(alternative_, alternative);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(condition_  .first);
             assert(consequent_ .first);
             assert(alternative_.first);
 
             if (is_true(condition_))
4068375e
                return consequent_.first->value();
             else
                return alternative_.first->value();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_conditional;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(condition_   , node_delete_list);
             expression_node<T>::ndb_t::collect(consequent_  , node_delete_list);
             expression_node<T>::ndb_t::collect(alternative_ , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
a65c8e8b
             return expression_node<T>::ndb_t::compute_node_depth
                (condition_, consequent_, alternative_);
4068375e
          }
 
       private:
 
a65c8e8b
          branch_t condition_;
4068375e
          branch_t consequent_;
          branch_t alternative_;
       };
 
       template <typename T>
a65c8e8b
       class cons_conditional_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          // Consequent only conditional statement node
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
a65c8e8b
          cons_conditional_node(expression_ptr condition,
4068375e
                                expression_ptr consequent)
          {
a65c8e8b
             construct_branch_pair(condition_ , condition );
4068375e
             construct_branch_pair(consequent_, consequent);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(condition_ .first);
             assert(consequent_.first);
 
             if (is_true(condition_))
4068375e
                return consequent_.first->value();
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_conditional;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(condition_  , node_delete_list);
             expression_node<T>::ndb_t::collect(consequent_ , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
a65c8e8b
             return expression_node<T>::ndb_t::
                compute_node_depth(condition_, consequent_);
4068375e
          }
 
       private:
 
a65c8e8b
          branch_t condition_;
4068375e
          branch_t consequent_;
       };
 
       #ifndef exprtk_disable_break_continue
       template <typename T>
       class break_exception
       {
       public:
 
a65c8e8b
          explicit break_exception(const T& v)
4068375e
          : value(v)
          {}
 
          T value;
       };
 
a65c8e8b
       class continue_exception {};
4068375e
 
       template <typename T>
a65c8e8b
       class break_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          break_node(expression_ptr ret = expression_ptr(0))
          {
             construct_branch_pair(return_, ret);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             const T result = return_.first ?
                              return_.first->value() :
                              std::numeric_limits<T>::quiet_NaN();
 
             throw break_exception<T>(result);
 
4068375e
             #ifndef _MSC_VER
             return std::numeric_limits<T>::quiet_NaN();
             #endif
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_break;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(return_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(return_);
          }
 
       private:
 
          branch_t return_;
       };
 
       template <typename T>
a65c8e8b
       class continue_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             throw continue_exception();
             #ifndef _MSC_VER
             return std::numeric_limits<T>::quiet_NaN();
             #endif
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_break;
          }
       };
       #endif
 
       struct loop_runtime_checker
       {
a65c8e8b
          loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check,
4068375e
                               loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid)
a65c8e8b
          : iteration_count_(0)
          , loop_runtime_check_(loop_runtime_check)
          , max_loop_iterations_(loop_runtime_check_->max_loop_iterations)
          , loop_type_(lp_typ)
          {
             assert(loop_runtime_check_);
          }
4068375e
 
          inline void reset(const _uint64_t initial_value = 0) const
          {
             iteration_count_ = initial_value;
          }
 
          inline bool check() const
          {
             if (
                  (0 == loop_runtime_check_) ||
a65c8e8b
                  (++iteration_count_ <= max_loop_iterations_)
4068375e
                )
             {
                return true;
             }
 
             loop_runtime_check::violation_context ctxt;
a65c8e8b
             ctxt.loop      = loop_type_;
4068375e
             ctxt.violation = loop_runtime_check::e_iteration_count;
 
             loop_runtime_check_->handle_runtime_violation(ctxt);
 
             return false;
          }
 
          mutable _uint64_t iteration_count_;
          mutable loop_runtime_check_ptr loop_runtime_check_;
a65c8e8b
          const details::_uint64_t& max_loop_iterations_;
          loop_runtime_check::loop_types loop_type_;
4068375e
       };
 
       template <typename T>
a65c8e8b
       class while_loop_node : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          while_loop_node(expression_ptr condition,
a65c8e8b
                          expression_ptr loop_body)
4068375e
          {
             construct_branch_pair(condition_, condition);
             construct_branch_pair(loop_body_, loop_body);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(condition_.first);
             assert(loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
a65c8e8b
             while (is_true(condition_))
4068375e
             {
                result = loop_body_.first->value();
             }
 
             return result;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_while;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(condition_ , node_delete_list);
             expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_);
          }
 
a65c8e8b
       protected:
4068375e
 
          branch_t condition_;
          branch_t loop_body_;
       };
 
       template <typename T>
a65c8e8b
       class while_loop_rtc_node exprtk_final
                                 : public while_loop_node<T>
                                 , public loop_runtime_checker
       {
       public:
 
          typedef while_loop_node<T>  parent_t;
          typedef expression_node<T>* expression_ptr;
 
          while_loop_rtc_node(expression_ptr condition,
                              expression_ptr loop_body,
                              loop_runtime_check_ptr loop_rt_chk)
          : parent_t(condition, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop)
          {}
 
          inline T value() const exprtk_override
          {
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
 
             T result = T(0);
 
             loop_runtime_checker::reset();
 
             while (is_true(parent_t::condition_) && loop_runtime_checker::check())
             {
                result = parent_t::loop_body_.first->value();
             }
 
             return result;
          }
       };
 
       template <typename T>
       class repeat_until_loop_node : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          repeat_until_loop_node(expression_ptr condition,
a65c8e8b
                                 expression_ptr loop_body)
4068375e
          {
             construct_branch_pair(condition_, condition);
             construct_branch_pair(loop_body_, loop_body);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(condition_.first);
             assert(loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
             do
             {
                result = loop_body_.first->value();
             }
a65c8e8b
             while (is_false(condition_.first));
4068375e
 
             return result;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_repeat;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(condition_ , node_delete_list);
             expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_);
          }
 
a65c8e8b
       protected:
4068375e
 
          branch_t condition_;
          branch_t loop_body_;
       };
 
       template <typename T>
a65c8e8b
       class repeat_until_loop_rtc_node exprtk_final
                                        : public repeat_until_loop_node<T>
                                        , public loop_runtime_checker
       {
       public:
 
          typedef repeat_until_loop_node<T> parent_t;
          typedef expression_node<T>*       expression_ptr;
 
          repeat_until_loop_rtc_node(expression_ptr condition,
                                     expression_ptr loop_body,
                                     loop_runtime_check_ptr loop_rt_chk)
          : parent_t(condition, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop)
          {}
 
          inline T value() const exprtk_override
          {
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
 
             T result = T(0);
 
             loop_runtime_checker::reset(1);
 
             do
             {
                result = parent_t::loop_body_.first->value();
             }
             while (is_false(parent_t::condition_.first) && loop_runtime_checker::check());
 
             return result;
          }
       };
 
       template <typename T>
       class for_loop_node : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          for_loop_node(expression_ptr initialiser,
                        expression_ptr condition,
                        expression_ptr incrementor,
a65c8e8b
                        expression_ptr loop_body)
4068375e
          {
             construct_branch_pair(initialiser_, initialiser);
             construct_branch_pair(condition_  , condition  );
             construct_branch_pair(incrementor_, incrementor);
             construct_branch_pair(loop_body_  , loop_body  );
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(condition_.first);
             assert(loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
             if (initialiser_.first)
                initialiser_.first->value();
 
             if (incrementor_.first)
             {
a65c8e8b
                while (is_true(condition_))
4068375e
                {
                   result = loop_body_.first->value();
                   incrementor_.first->value();
                }
             }
             else
             {
a65c8e8b
                while (is_true(condition_))
4068375e
                {
                   result = loop_body_.first->value();
                }
             }
 
             return result;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_for;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(initialiser_ , node_delete_list);
             expression_node<T>::ndb_t::collect(condition_   , node_delete_list);
             expression_node<T>::ndb_t::collect(incrementor_ , node_delete_list);
             expression_node<T>::ndb_t::collect(loop_body_   , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth
                (initialiser_, condition_, incrementor_, loop_body_);
          }
 
a65c8e8b
       protected:
4068375e
 
          branch_t initialiser_;
          branch_t condition_  ;
          branch_t incrementor_;
          branch_t loop_body_  ;
       };
 
       template <typename T>
a65c8e8b
       class for_loop_rtc_node exprtk_final
                               : public for_loop_node<T>
                               , public loop_runtime_checker
4068375e
       {
       public:
 
a65c8e8b
          typedef for_loop_node<T>    parent_t;
4068375e
          typedef expression_node<T>* expression_ptr;
 
a65c8e8b
          for_loop_rtc_node(expression_ptr initialiser,
                            expression_ptr condition,
                            expression_ptr incrementor,
                            expression_ptr loop_body,
                            loop_runtime_check_ptr loop_rt_chk)
          : parent_t(initialiser, condition, incrementor, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop)
          {}
4068375e
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
 
4068375e
             T result = T(0);
 
             loop_runtime_checker::reset();
 
a65c8e8b
             if (parent_t::initialiser_.first)
                parent_t::initialiser_.first->value();
 
             if (parent_t::incrementor_.first)
             {
                while (is_true(parent_t::condition_) && loop_runtime_checker::check())
                {
                   result = parent_t::loop_body_.first->value();
                   parent_t::incrementor_.first->value();
                }
             }
             else
             {
                while (is_true(parent_t::condition_) && loop_runtime_checker::check())
                {
                   result = parent_t::loop_body_.first->value();
                }
             }
 
             return result;
          }
       };
 
       #ifndef exprtk_disable_break_continue
       template <typename T>
       class while_loop_bc_node : public while_loop_node<T>
       {
       public:
 
          typedef while_loop_node<T>  parent_t;
          typedef expression_node<T>* expression_ptr;
 
          while_loop_bc_node(expression_ptr condition,
                             expression_ptr loop_body)
          : parent_t(condition, loop_body)
          {}
 
          inline T value() const exprtk_override
          {
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
 
             T result = T(0);
 
             while (is_true(parent_t::condition_))
4068375e
             {
                try
                {
a65c8e8b
                   result = parent_t::loop_body_.first->value();
4068375e
                }
                catch(const break_exception<T>& e)
                {
                   return e.value;
                }
                catch(const continue_exception&)
                {}
             }
 
             return result;
          }
a65c8e8b
       };
4068375e
 
a65c8e8b
       template <typename T>
       class while_loop_bc_rtc_node exprtk_final
                                    : public while_loop_bc_node<T>
                                    , public loop_runtime_checker
       {
       public:
4068375e
 
a65c8e8b
          typedef while_loop_bc_node<T> parent_t;
          typedef expression_node<T>*   expression_ptr;
4068375e
 
a65c8e8b
          while_loop_bc_rtc_node(expression_ptr condition,
                                 expression_ptr loop_body,
                                 loop_runtime_check_ptr loop_rt_chk)
          : parent_t(condition, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop)
          {}
 
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
a65c8e8b
             loop_runtime_checker::reset();
 
             while (is_true(parent_t::condition_) && loop_runtime_checker::check())
             {
                try
                {
                   result = parent_t::loop_body_.first->value();
                }
                catch(const break_exception<T>& e)
                {
                   return e.value;
                }
                catch(const continue_exception&)
                {}
             }
 
             return result;
          }
4068375e
       };
 
       template <typename T>
a65c8e8b
       class repeat_until_loop_bc_node : public repeat_until_loop_node<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef repeat_until_loop_node<T> parent_t;
          typedef expression_node<T>*       expression_ptr;
4068375e
 
          repeat_until_loop_bc_node(expression_ptr condition,
a65c8e8b
                                    expression_ptr loop_body)
          : parent_t(condition, loop_body)
          {}
4068375e
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
             do
             {
                try
                {
a65c8e8b
                   result = parent_t::loop_body_.first->value();
4068375e
                }
                catch(const break_exception<T>& e)
                {
                   return e.value;
                }
                catch(const continue_exception&)
                {}
             }
a65c8e8b
             while (is_false(parent_t::condition_.first));
4068375e
 
             return result;
          }
a65c8e8b
       };
4068375e
 
a65c8e8b
       template <typename T>
       class repeat_until_loop_bc_rtc_node exprtk_final
                                           : public repeat_until_loop_bc_node<T>,
                                             public loop_runtime_checker
       {
       public:
4068375e
 
a65c8e8b
          typedef repeat_until_loop_bc_node<T> parent_t;
          typedef expression_node<T>*          expression_ptr;
4068375e
 
a65c8e8b
          repeat_until_loop_bc_rtc_node(expression_ptr condition,
                                        expression_ptr loop_body,
                                        loop_runtime_check_ptr loop_rt_chk)
          : parent_t(condition, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop)
          {}
 
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
a65c8e8b
             loop_runtime_checker::reset();
 
             do
             {
                try
                {
                   result = parent_t::loop_body_.first->value();
                }
                catch(const break_exception<T>& e)
                {
                   return e.value;
                }
                catch(const continue_exception&)
                {}
             }
             while (is_false(parent_t::condition_.first) && loop_runtime_checker::check());
 
             return result;
          }
4068375e
       };
 
       template <typename T>
a65c8e8b
       class for_loop_bc_node : public for_loop_node<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef for_loop_node<T>    parent_t;
4068375e
          typedef expression_node<T>* expression_ptr;
 
          for_loop_bc_node(expression_ptr initialiser,
                           expression_ptr condition,
                           expression_ptr incrementor,
a65c8e8b
                           expression_ptr loop_body)
          : parent_t(initialiser, condition, incrementor, loop_body)
          {}
4068375e
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
 
4068375e
             T result = T(0);
 
a65c8e8b
             if (parent_t::initialiser_.first)
                parent_t::initialiser_.first->value();
4068375e
 
a65c8e8b
             if (parent_t::incrementor_.first)
4068375e
             {
a65c8e8b
                while (is_true(parent_t::condition_))
4068375e
                {
                   try
                   {
a65c8e8b
                      result = parent_t::loop_body_.first->value();
4068375e
                   }
                   catch(const break_exception<T>& e)
                   {
                      return e.value;
                   }
                   catch(const continue_exception&)
                   {}
 
a65c8e8b
                   parent_t::incrementor_.first->value();
4068375e
                }
             }
             else
             {
a65c8e8b
                while (is_true(parent_t::condition_))
4068375e
                {
                   try
                   {
a65c8e8b
                      result = parent_t::loop_body_.first->value();
4068375e
                   }
                   catch(const break_exception<T>& e)
                   {
                      return e.value;
                   }
                   catch(const continue_exception&)
                   {}
                }
             }
 
             return result;
          }
a65c8e8b
       };
4068375e
 
a65c8e8b
       template <typename T>
       class for_loop_bc_rtc_node exprtk_final
                                  : public for_loop_bc_node<T>
                                  , public loop_runtime_checker
       {
       public:
4068375e
 
a65c8e8b
          typedef for_loop_bc_node<T> parent_t;
          typedef expression_node<T>* expression_ptr;
 
          for_loop_bc_rtc_node(expression_ptr initialiser,
                               expression_ptr condition,
                               expression_ptr incrementor,
                               expression_ptr loop_body,
                               loop_runtime_check_ptr loop_rt_chk)
          : parent_t(initialiser, condition, incrementor, loop_body)
          , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop)
          {}
4068375e
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(parent_t::condition_.first);
             assert(parent_t::loop_body_.first);
4068375e
 
a65c8e8b
             T result = T(0);
4068375e
 
a65c8e8b
             loop_runtime_checker::reset();
 
             if (parent_t::initialiser_.first)
                parent_t::initialiser_.first->value();
 
             if (parent_t::incrementor_.first)
             {
                while (is_true(parent_t::condition_) && loop_runtime_checker::check())
                {
                   try
                   {
                      result = parent_t::loop_body_.first->value();
                   }
                   catch(const break_exception<T>& e)
                   {
                      return e.value;
                   }
                   catch(const continue_exception&)
                   {}
 
                   parent_t::incrementor_.first->value();
                }
             }
             else
             {
                while (is_true(parent_t::condition_) && loop_runtime_checker::check())
                {
                   try
                   {
                      result = parent_t::loop_body_.first->value();
                   }
                   catch(const break_exception<T>& e)
                   {
                      return e.value;
                   }
                   catch(const continue_exception&)
                   {}
                }
             }
 
             return result;
          }
4068375e
       };
       #endif
 
       template <typename T>
       class switch_node : public expression_node<T>
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          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());
 
             for (std::size_t i = 0; i < arg_list.size(); ++i)
             {
                if (arg_list[i])
                {
                   construct_branch_pair(arg_list_[i], arg_list[i]);
                }
                else
                {
                   arg_list_.clear();
                   return;
                }
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             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    ].first;
                   expression_ptr consequent = arg_list_[i + 1].first;
 
                   if (is_true(condition))
                   {
                      return consequent->value();
                   }
                }
 
                return arg_list_[upper_bound].first->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::e_switch;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(arg_list_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
 
       protected:
 
          std::vector<branch_t> arg_list_;
       };
 
       template <typename T, typename Switch_N>
a65c8e8b
       class switch_n_node exprtk_final : public switch_node<T>
4068375e
       {
       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)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Switch_N::process(switch_node<T>::arg_list_);
          }
       };
 
       template <typename T>
a65c8e8b
       class multi_switch_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          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());
 
             for (std::size_t i = 0; i < arg_list.size(); ++i)
             {
                if (arg_list[i])
                {
                   construct_branch_pair(arg_list_[i], arg_list[i]);
                }
                else
                {
                   arg_list_.clear();
                   return;
                }
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             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    ].first;
                expression_ptr consequent = arg_list_[i + 1].first;
 
                if (is_true(condition))
                {
                   result = consequent->value();
                }
             }
 
             return result;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_mswitch;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(arg_list_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
 
       private:
 
          std::vector<branch_t> arg_list_;
       };
 
       template <typename T>
       class ivariable
       {
       public:
 
a65c8e8b
          virtual ~ivariable() {}
4068375e
 
          virtual T& ref() = 0;
          virtual const T& ref() const = 0;
       };
 
       template <typename T>
a65c8e8b
       class variable_node exprtk_final
                           : public expression_node<T>,
4068375e
                             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);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return (*value_);
          }
 
a65c8e8b
          inline T& ref() exprtk_override
4068375e
          {
             return (*value_);
          }
 
a65c8e8b
          inline const T& ref() const exprtk_override
4068375e
          {
             return (*value_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             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()
a65c8e8b
          : 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))
4068375e
          {}
 
          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);
                }
             }
          }
 
a65c8e8b
          bool const_range() const
4068375e
          {
            return ( n0_c.first &&  n1_c.first) &&
                   (!n0_e.first && !n1_e.first);
          }
 
a65c8e8b
          bool var_range() const
4068375e
          {
            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)
             {
a65c8e8b
                r0 = static_cast<std::size_t>(details::numeric::to_int64(n0_e.second->value()));
4068375e
             }
             else
                return false;
 
             if (n1_c.first)
                r1 = n1_c.second;
             else if (n1_e.first)
             {
a65c8e8b
                r1 = static_cast<std::size_t>(details::numeric::to_int64(n1_e.second->value()));
4068375e
             }
             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;
 
a65c8e8b
             #ifndef exprtk_enable_range_runtime_checks
4068375e
             return (r0 <= r1);
a65c8e8b
             #else
             return range_runtime_check(r0, r1, size);
             #endif
4068375e
          }
 
          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;
a65c8e8b
 
          #ifdef exprtk_enable_range_runtime_checks
          bool range_runtime_check(const std::size_t r0,
                                   const std::size_t r1,
                                   const std::size_t size) const
          {
             if (r0 >= size)
             {
                throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)");
                return false;
             }
 
             if (r1 >= size)
             {
                throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)");
                return false;
             }
 
             return (r0 <= r1);
          }
          #endif
4068375e
       };
 
       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()
a65c8e8b
          : range(0)
          , data (0)
          , size (0)
          , type_size(0)
          , str_node (0)
4068375e
          {}
 
          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;
a65c8e8b
          typedef vec_data_store<T> vds_t;
4068375e
 
a65c8e8b
          virtual ~vector_interface() {}
4068375e
 
          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>
a65c8e8b
       class vector_node exprtk_final
                         : public expression_node <T>
                         , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
4068375e
          typedef vector_holder<T>    vector_holder_t;
          typedef vector_node<T>*     vector_node_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          explicit vector_node(vector_holder_t* vh)
a65c8e8b
          : vector_holder_(vh)
          , vds_((*vector_holder_).size(),(*vector_holder_)[0])
4068375e
          {
             vector_holder_->set_ref(&vds_.ref());
          }
 
          vector_node(const vds_t& vds, vector_holder_t* vh)
a65c8e8b
          : vector_holder_(vh)
          , vds_(vds)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return vds().data()[0];
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return const_cast<vector_node_ptr>(this);
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return this;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vector;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
          inline vector_holder_t& vec_holder()
          {
             return (*vector_holder_);
          }
 
       private:
 
          vector_holder_t* vector_holder_;
          vds_t                      vds_;
       };
 
       template <typename T>
a65c8e8b
       class vector_elem_node exprtk_final
                              : public expression_node<T>,
4068375e
                                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 std::pair<expression_ptr,bool> branch_t;
 
          vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder)
a65c8e8b
          : vec_holder_(vec_holder)
          , vector_base_((*vec_holder)[0])
4068375e
          {
             construct_branch_pair(index_, index);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline T& ref() exprtk_override
4068375e
          {
             return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline const T& ref() const exprtk_override
4068375e
          {
             return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecelem;
          }
 
          inline vector_holder_t& vec_holder()
          {
             return (*vec_holder_);
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(index_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(index_);
          }
 
       private:
 
          vector_holder_ptr vec_holder_;
          T* vector_base_;
          branch_t index_;
       };
 
       template <typename T>
a65c8e8b
       class rebasevector_elem_node exprtk_final
                                    : public expression_node<T>,
4068375e
                                      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;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder)
a65c8e8b
          : vector_holder_(vec_holder)
          , vds_((*vector_holder_).size(),(*vector_holder_)[0])
4068375e
          {
             vector_holder_->set_ref(&vds_.ref());
             construct_branch_pair(index_, index);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline T& ref() exprtk_override
4068375e
          {
             return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline const T& ref() const exprtk_override
4068375e
          {
             return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value())));
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_rbvecelem;
          }
 
          inline vector_holder_t& vec_holder()
          {
             return (*vector_holder_);
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(index_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(index_);
          }
 
       private:
 
          vector_holder_ptr vector_holder_;
          vds_t             vds_;
          branch_t          index_;
       };
 
       template <typename T>
a65c8e8b
       class rebasevector_celem_node exprtk_final
                                     : public expression_node<T>,
4068375e
                                       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)
a65c8e8b
          : index_(index)
          , vector_holder_(vec_holder)
          , vds_((*vector_holder_).size(),(*vector_holder_)[0])
4068375e
          {
             vector_holder_->set_ref(&vds_.ref());
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return *(vds_.data() + index_);
          }
 
a65c8e8b
          inline T& ref() exprtk_override
4068375e
          {
             return *(vds_.data() + index_);
          }
 
a65c8e8b
          inline const T& ref() const exprtk_override
4068375e
          {
             return *(vds_.data() + index_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             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>
a65c8e8b
       class vector_assignment_node exprtk_final : public expression_node<T>
4068375e
       {
       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)
a65c8e8b
          : vector_base_(vector_base)
          , initialiser_list_(initialiser_list)
          , size_(size)
          , single_value_initialse_(single_value_initialse)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (single_value_initialse_)
             {
                for (std::size_t i = 0; i < size_; ++i)
                {
                   *(vector_base_ + i) = initialiser_list_[0]->value();
                }
             }
             else
             {
a65c8e8b
                const std::size_t initialiser_list_size = initialiser_list_.size();
4068375e
 
a65c8e8b
                for (std::size_t i = 0; i < initialiser_list_size; ++i)
4068375e
                {
                   *(vector_base_ + i) = initialiser_list_[i]->value();
                }
 
a65c8e8b
                if (initialiser_list_size < size_)
4068375e
                {
a65c8e8b
                   for (std::size_t i = initialiser_list_size; i < size_; ++i)
4068375e
                   {
                      *(vector_base_ + i) = T(0);
                   }
                }
             }
 
             return *(vector_base_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecdefass;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_);
          }
 
       private:
 
a65c8e8b
          vector_assignment_node(const vector_assignment_node<T>&) exprtk_delete;
          vector_assignment_node<T>& operator=(const vector_assignment_node<T>&) exprtk_delete;
4068375e
 
          mutable T* vector_base_;
          std::vector<expression_ptr> initialiser_list_;
          const std::size_t size_;
          const bool single_value_initialse_;
       };
 
       template <typename T>
a65c8e8b
       class swap_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef variable_node<T>*   variable_node_ptr;
 
          swap_node(variable_node_ptr var0, variable_node_ptr var1)
a65c8e8b
          : var0_(var0)
          , var1_(var1)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             std::swap(var0_->ref(),var1_->ref());
             return var1_->ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_swap;
          }
 
       private:
 
          variable_node_ptr var0_;
          variable_node_ptr var1_;
       };
 
       template <typename T>
a65c8e8b
       class swap_generic_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
a65c8e8b
          typedef ivariable<T>*       ivariable_ptr;
4068375e
 
          swap_generic_node(expression_ptr var0, expression_ptr var1)
a65c8e8b
          : binary_node<T>(details::e_swap, var0, var1)
          , var0_(dynamic_cast<ivariable_ptr>(var0))
          , var1_(dynamic_cast<ivariable_ptr>(var1))
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             std::swap(var0_->ref(),var1_->ref());
             return var1_->ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_swap;
          }
 
       private:
 
          ivariable_ptr var0_;
          ivariable_ptr var1_;
       };
 
       template <typename T>
a65c8e8b
       class swap_vecvec_node exprtk_final
                              : public binary_node     <T>
                              , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
          typedef vector_node    <T>* vector_node_ptr;
          typedef vec_data_store <T>  vds_t;
4068375e
 
          swap_vecvec_node(expression_ptr branch0,
                           expression_ptr branch1)
a65c8e8b
          : binary_node<T>(details::e_swap, branch0, branch1)
          , vec0_node_ptr_(0)
          , vec1_node_ptr_(0)
          , vec_size_     (0)
          , initialised_  (false)
4068375e
          {
             if (is_ivector_node(binary_node<T>::branch_[0].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
                {
                   vec0_node_ptr_ = vi->vec();
                   vds()          = vi->vds();
                }
             }
 
             if (is_ivector_node(binary_node<T>::branch_[1].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
                {
                   vec1_node_ptr_ = vi->vec();
                }
             }
 
             if (vec0_node_ptr_ && vec1_node_ptr_)
             {
                vec_size_ = std::min(vec0_node_ptr_->vds().size(),
                                     vec1_node_ptr_->vds().size());
 
                initialised_ = true;
             }
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                T* vec0 = vec0_node_ptr_->vds().data();
                T* vec1 = vec1_node_ptr_->vds().data();
 
                for (std::size_t i = 0; i < vec_size_; ++i)
                {
                   std::swap(vec0[i],vec1[i]);
                }
 
                return vec1_node_ptr_->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvecswap;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vec_size_;
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node<T>* vec0_node_ptr_;
          vector_node<T>* vec1_node_ptr_;
          std::size_t     vec_size_;
          bool            initialised_;
          vds_t           vds_;
       };
 
       #ifndef exprtk_disable_string_capabilities
       template <typename T>
a65c8e8b
       class stringvar_node exprtk_final
                            : public expression_node <T>,
4068375e
                              public string_base_node<T>,
                              public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
4068375e
 
          static std::string null_value;
 
          explicit stringvar_node()
          : value_(&null_value)
          {}
 
          explicit stringvar_node(std::string& v)
          : value_(&v)
          {
             rp_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1);
             rp_.cache.first  = rp_.n0_c.second;
             rp_.cache.second = rp_.n1_c.second;
          }
 
          inline bool operator <(const stringvar_node<T>& v) const
          {
             return this < (&v);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             rp_.n1_c.second  = (*value_).size() - 1;
             rp_.cache.second = rp_.n1_c.second;
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return ref();
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return &(*value_)[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return ref().size();
          }
 
          std::string& ref()
          {
             return (*value_);
          }
 
          const std::string& ref() const
          {
             return (*value_);
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringvar;
          }
 
a65c8e8b
          void rebase(std::string& s)
          {
             value_ = &s;
             rp_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             rp_.n1_c = std::make_pair<bool,std::size_t>(true,value_->size() - 1);
             rp_.cache.first  = rp_.n0_c.second;
             rp_.cache.second = rp_.n1_c.second;
          }
 
4068375e
       private:
 
          std::string* value_;
          mutable range_t rp_;
       };
 
       template <typename T>
       std::string stringvar_node<T>::null_value = std::string("");
 
       template <typename T>
a65c8e8b
       class string_range_node exprtk_final
                               : public expression_node <T>,
4068375e
                                 public string_base_node<T>,
                                 public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
4068375e
 
          static std::string null_value;
 
          explicit string_range_node(std::string& v, const range_t& rp)
a65c8e8b
          : value_(&v)
          , rp_(rp)
4068375e
          {}
 
          virtual ~string_range_node()
          {
             rp_.free();
          }
 
          inline bool operator <(const string_range_node<T>& v) const
          {
             return this < (&v);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline std::string str() const exprtk_override
4068375e
          {
             return (*value_);
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return &(*value_)[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return ref().size();
          }
 
          inline range_t range() const
          {
             return rp_;
          }
 
          inline virtual std::string& ref()
          {
             return (*value_);
          }
 
          inline virtual const std::string& ref() const
          {
             return (*value_);
          }
 
a65c8e8b
          inline range_t& range_ref() exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          inline const range_t& range_ref() const exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringvarrng;
          }
 
       private:
 
          std::string* value_;
          range_t      rp_;
       };
 
       template <typename T>
       std::string string_range_node<T>::null_value = std::string("");
 
       template <typename T>
a65c8e8b
       class const_string_range_node exprtk_final
                                     : public expression_node <T>,
4068375e
                                       public string_base_node<T>,
                                       public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
4068375e
 
          explicit const_string_range_node(const std::string& v, const range_t& rp)
a65c8e8b
          : value_(v)
          , rp_(rp)
4068375e
          {}
 
         ~const_string_range_node()
          {
             rp_.free();
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return value_.data();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return value_.size();
          }
 
          range_t range() const
          {
             return rp_;
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return rp_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_cstringvarrng;
          }
 
       private:
 
a65c8e8b
          const_string_range_node(const const_string_range_node<T>&) exprtk_delete;
          const_string_range_node<T>& operator=(const const_string_range_node<T>&) exprtk_delete;
4068375e
 
          const std::string value_;
          range_t rp_;
       };
 
       template <typename T>
a65c8e8b
       class generic_string_range_node exprtk_final
                                       : public expression_node <T>,
4068375e
                                         public string_base_node<T>,
                                         public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef expression_node <T>* expression_ptr;
          typedef stringvar_node  <T>* strvar_node_ptr;
          typedef string_base_node<T>* str_base_ptr;
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface<T>   irange_t;
          typedef irange_t*            irange_ptr;
4068375e
          typedef std::pair<expression_ptr,bool>  branch_t;
 
          generic_string_range_node(expression_ptr str_branch, const range_t& brange)
a65c8e8b
          : initialised_(false)
          , str_base_ptr_ (0)
          , str_range_ptr_(0)
          , base_range_(brange)
4068375e
          {
             range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
             range_.cache.first  = range_.n0_c.second;
             range_.cache.second = range_.n1_c.second;
 
             construct_branch_pair(branch_, str_branch);
 
             if (is_generally_string_node(branch_.first))
             {
                str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_.first);
 
                if (0 == str_base_ptr_)
                   return;
 
                str_range_ptr_ = dynamic_cast<irange_ptr>(branch_.first);
 
                if (0 == str_range_ptr_)
                   return;
             }
 
             initialised_ = (str_base_ptr_ && str_range_ptr_);
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
         ~generic_string_range_node()
          {
             base_range_.free();
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(branch_.first);
 
4068375e
                branch_.first->value();
 
                std::size_t str_r0 = 0;
                std::size_t str_r1 = 0;
 
                std::size_t r0 = 0;
                std::size_t r1 = 0;
 
a65c8e8b
                const range_t& range = str_range_ptr_->range_ref();
4068375e
 
                const std::size_t base_str_size = str_base_ptr_->size();
 
                if (
                     range      (str_r0, str_r1, base_str_size) &&
a65c8e8b
                     base_range_(    r0,     r1, base_str_size - str_r0)
4068375e
                   )
                {
                   const std::size_t size = (r1 - r0) + 1;
 
                   range_.n1_c.second  = size - 1;
                   range_.cache.second = range_.n1_c.second;
 
                   value_.assign(str_base_ptr_->base() + str_r0 + r0, size);
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return &value_[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return value_.size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strgenrange;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
          bool                initialised_;
a65c8e8b
          branch_t            branch_;
          str_base_ptr        str_base_ptr_;
          irange_ptr          str_range_ptr_;
          mutable range_t     base_range_;
          mutable range_t     range_;
          mutable std::string value_;
4068375e
       };
 
       template <typename T>
a65c8e8b
       class string_concat_node exprtk_final
                                : public binary_node     <T>,
4068375e
                                  public string_base_node<T>,
                                  public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_interface<T>   irange_t;
          typedef irange_t*            irange_ptr;
          typedef range_t*             range_ptr;
          typedef expression_node <T>* expression_ptr;
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
          string_concat_node(const operator_type& opr,
                             expression_ptr branch0,
                             expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , initialised_(false)
          , str0_base_ptr_ (0)
          , str1_base_ptr_ (0)
          , str0_range_ptr_(0)
          , str1_range_ptr_(0)
4068375e
          {
             range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
 
             range_.cache.first  = range_.n0_c.second;
             range_.cache.second = range_.n1_c.second;
 
             if (is_generally_string_node(binary_node<T>::branch_[0].first))
             {
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_base_ptr_)
                   return;
 
                str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_range_ptr_)
                   return;
             }
 
             if (is_generally_string_node(binary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                str1_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_range_ptr_)
                   return;
             }
 
             initialised_ = str0_base_ptr_  &&
                            str1_base_ptr_  &&
                            str0_range_ptr_ &&
                            str1_range_ptr_ ;
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                std::size_t str0_r0 = 0;
                std::size_t str0_r1 = 0;
 
                std::size_t str1_r0 = 0;
                std::size_t str1_r1 = 0;
 
a65c8e8b
                const range_t& range0 = str0_range_ptr_->range_ref();
                const range_t& range1 = str1_range_ptr_->range_ref();
4068375e
 
                if (
                     range0(str0_r0, str0_r1, str0_base_ptr_->size()) &&
                     range1(str1_r0, str1_r1, str1_base_ptr_->size())
                   )
                {
                   const std::size_t size0 = (str0_r1 - str0_r0) + 1;
                   const std::size_t size1 = (str1_r1 - str1_r0) + 1;
 
                   value_.assign(str0_base_ptr_->base() + str0_r0, size0);
                   value_.append(str1_base_ptr_->base() + str1_r0, size1);
 
                   range_.n1_c.second  = value_.size() - 1;
                   range_.cache.second = range_.n1_c.second;
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return &value_[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return value_.size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strconcat;
          }
 
       private:
 
a65c8e8b
          bool                initialised_;
          str_base_ptr        str0_base_ptr_;
          str_base_ptr        str1_base_ptr_;
          irange_ptr          str0_range_ptr_;
          irange_ptr          str1_range_ptr_;
4068375e
          mutable range_t     range_;
          mutable std::string value_;
       };
 
       template <typename T>
a65c8e8b
       class swap_string_node exprtk_final
                              : public binary_node     <T>,
4068375e
                                public string_base_node<T>,
                                public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface<T>   irange_t;
          typedef irange_t*            irange_ptr;
          typedef expression_node <T>* expression_ptr;
4068375e
          typedef stringvar_node  <T>* strvar_node_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
          swap_string_node(expression_ptr branch0, expression_ptr branch1)
          : binary_node<T>(details::e_swap, branch0, branch1),
            initialised_(false),
            str0_node_ptr_(0),
            str1_node_ptr_(0)
          {
             if (is_string_node(binary_node<T>::branch_[0].first))
             {
                str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first);
             }
 
             if (is_string_node(binary_node<T>::branch_[1].first))
             {
                str1_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[1].first);
             }
 
             initialised_ = (str0_node_ptr_ && str1_node_ptr_);
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref());
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return str0_node_ptr_->str();
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
            return str0_node_ptr_->base();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return str0_node_ptr_->size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return str0_node_ptr_->range_ref();
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return str0_node_ptr_->range_ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strswap;
          }
 
       private:
 
          bool initialised_;
          strvar_node_ptr str0_node_ptr_;
          strvar_node_ptr str1_node_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class swap_genstrings_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface<T>   irange_t;
          typedef irange_t*            irange_ptr;
4068375e
          typedef expression_node <T>* expression_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
          swap_genstrings_node(expression_ptr branch0,
                               expression_ptr branch1)
a65c8e8b
          : binary_node<T>(details::e_default, branch0, branch1)
          , str0_base_ptr_ (0)
          , str1_base_ptr_ (0)
          , str0_range_ptr_(0)
          , str1_range_ptr_(0)
          , initialised_(false)
4068375e
          {
             if (is_generally_string_node(binary_node<T>::branch_[0].first))
             {
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == range)
                   return;
 
                str0_range_ptr_ = &(range->range_ref());
             }
 
             if (is_generally_string_node(binary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == range)
                   return;
 
                str1_range_ptr_ = &(range->range_ref());
             }
 
             initialised_ = str0_base_ptr_  &&
                            str1_base_ptr_  &&
                            str0_range_ptr_ &&
                            str1_range_ptr_ ;
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                std::size_t str0_r0 = 0;
                std::size_t str0_r1 = 0;
 
                std::size_t str1_r0 = 0;
                std::size_t str1_r1 = 0;
 
a65c8e8b
                const range_t& range0 = (*str0_range_ptr_);
                const range_t& range1 = (*str1_range_ptr_);
4068375e
 
                if (
                     range0(str0_r0, str0_r1, str0_base_ptr_->size()) &&
                     range1(str1_r0, str1_r1, str1_base_ptr_->size())
                   )
                {
                   const std::size_t size0    = range0.cache_size();
                   const std::size_t size1    = range1.cache_size();
                   const std::size_t max_size = std::min(size0,size1);
 
                   char_ptr s0 = const_cast<char_ptr>(str0_base_ptr_->base() + str0_r0);
                   char_ptr s1 = const_cast<char_ptr>(str1_base_ptr_->base() + str1_r0);
 
                   loop_unroll::details lud(max_size);
                   char_cptr upper_bound = s0 + lud.upper_bound;
 
                   while (s0 < upper_bound)
                   {
                      #define exprtk_loop(N)   \
                      std::swap(s0[N], s1[N]); \
 
                      exprtk_loop( 0) exprtk_loop( 1)
                      exprtk_loop( 2) exprtk_loop( 3)
                      #ifndef exprtk_disable_superscalar_unroll
                      exprtk_loop( 4) exprtk_loop( 5)
                      exprtk_loop( 6) exprtk_loop( 7)
                      exprtk_loop( 8) exprtk_loop( 9)
                      exprtk_loop(10) exprtk_loop(11)
                      exprtk_loop(12) exprtk_loop(13)
                      exprtk_loop(14) exprtk_loop(15)
                      #endif
 
                      s0 += lud.batch_size;
                      s1 += lud.batch_size;
                   }
 
                   int i = 0;
 
                   exprtk_disable_fallthrough_begin
                   switch (lud.remainder)
                   {
                      #define case_stmt(N)                       \
                      case N : { std::swap(s0[i], s1[i]); ++i; } \
 
                      #ifndef exprtk_disable_superscalar_unroll
                      case_stmt(15) case_stmt(14)
                      case_stmt(13) case_stmt(12)
                      case_stmt(11) case_stmt(10)
                      case_stmt( 9) case_stmt( 8)
                      case_stmt( 7) case_stmt( 6)
                      case_stmt( 5) case_stmt( 4)
                      #endif
                      case_stmt( 3) case_stmt( 2)
                      case_stmt( 1)
                   }
                   exprtk_disable_fallthrough_end
 
                   #undef exprtk_loop
                   #undef case_stmt
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strswap;
          }
 
       private:
 
a65c8e8b
          swap_genstrings_node(const swap_genstrings_node<T>&) exprtk_delete;
          swap_genstrings_node<T>& operator=(const swap_genstrings_node<T>&) exprtk_delete;
4068375e
 
          str_base_ptr str0_base_ptr_;
          str_base_ptr str1_base_ptr_;
          range_ptr    str0_range_ptr_;
          range_ptr    str1_range_ptr_;
          bool         initialised_;
       };
 
       template <typename T>
a65c8e8b
       class stringvar_size_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          static std::string null_value;
 
          explicit stringvar_size_node()
          : value_(&null_value)
          {}
 
          explicit stringvar_size_node(std::string& v)
          : value_(&v)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return T((*value_).size());
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringvarsize;
          }
 
       private:
 
          std::string* value_;
       };
 
       template <typename T>
       std::string stringvar_size_node<T>::null_value = std::string("");
 
       template <typename T>
a65c8e8b
       class string_size_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node <T>* expression_ptr;
          typedef string_base_node<T>* str_base_ptr;
4068375e
          typedef std::pair<expression_ptr,bool>  branch_t;
 
          explicit string_size_node(expression_ptr branch)
          : str_base_ptr_(0)
          {
             construct_branch_pair(branch_, branch);
 
             if (is_generally_string_node(branch_.first))
             {
                str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_.first);
 
                if (0 == str_base_ptr_)
                   return;
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             T result = std::numeric_limits<T>::quiet_NaN();
 
             if (str_base_ptr_)
             {
                branch_.first->value();
                result = T(str_base_ptr_->size());
             }
 
             return result;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringsize;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
          branch_t           branch_;
          str_base_ptr str_base_ptr_;
       };
 
       struct asn_assignment
       {
          static inline void execute(std::string& s, char_cptr data, const std::size_t size)
          { s.assign(data,size); }
       };
 
       struct asn_addassignment
       {
          static inline void execute(std::string& s, char_cptr data, const std::size_t size)
          { s.append(data,size); }
       };
 
       template <typename T, typename AssignmentProcess = asn_assignment>
a65c8e8b
       class assignment_string_node exprtk_final
                                    : public binary_node     <T>,
4068375e
                                      public string_base_node<T>,
                                      public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface <T>  irange_t;
          typedef irange_t*            irange_ptr;
          typedef expression_node <T>* expression_ptr;
4068375e
          typedef stringvar_node  <T>* strvar_node_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
          assignment_string_node(const operator_type& opr,
                                 expression_ptr branch0,
                                 expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , initialised_(false)
          , str0_base_ptr_ (0)
          , str1_base_ptr_ (0)
          , str0_node_ptr_ (0)
          , str1_range_ptr_(0)
4068375e
          {
             if (is_string_node(binary_node<T>::branch_[0].first))
             {
                str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first);
 
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
             }
 
             if (is_generally_string_node(binary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == range)
                   return;
 
                str1_range_ptr_ = &(range->range_ref());
             }
 
             initialised_ = str0_base_ptr_  &&
                            str1_base_ptr_  &&
                            str0_node_ptr_  &&
                            str1_range_ptr_ ;
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[1].first->value();
 
                std::size_t r0 = 0;
                std::size_t r1 = 0;
 
a65c8e8b
                const range_t& range = (*str1_range_ptr_);
4068375e
 
                if (range(r0, r1, str1_base_ptr_->size()))
                {
                   AssignmentProcess::execute(str0_node_ptr_->ref(),
                                              str1_base_ptr_->base() + r0,
                                              (r1 - r0) + 1);
 
                   binary_node<T>::branch_[0].first->value();
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return str0_node_ptr_->str();
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
            return str0_node_ptr_->base();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return str0_node_ptr_->size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return str0_node_ptr_->range_ref();
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return str0_node_ptr_->range_ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strass;
          }
 
       private:
 
          bool            initialised_;
          str_base_ptr    str0_base_ptr_;
          str_base_ptr    str1_base_ptr_;
          strvar_node_ptr str0_node_ptr_;
          range_ptr       str1_range_ptr_;
       };
 
       template <typename T, typename AssignmentProcess = asn_assignment>
a65c8e8b
       class assignment_string_range_node exprtk_final
                                          : public binary_node     <T>,
4068375e
                                            public string_base_node<T>,
                                            public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*              range_ptr;
          typedef range_interface  <T>  irange_t;
          typedef irange_t*             irange_ptr;
          typedef expression_node  <T>* expression_ptr;
          typedef stringvar_node   <T>* strvar_node_ptr;
4068375e
          typedef string_range_node<T>* str_rng_node_ptr;
a65c8e8b
          typedef string_base_node <T>* str_base_ptr;
4068375e
 
          assignment_string_range_node(const operator_type& opr,
                                       expression_ptr branch0,
                                       expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , initialised_(false)
          , str0_base_ptr_    (0)
          , str1_base_ptr_    (0)
          , str0_rng_node_ptr_(0)
          , str0_range_ptr_   (0)
          , str1_range_ptr_   (0)
4068375e
          {
             if (is_string_range_node(binary_node<T>::branch_[0].first))
             {
                str0_rng_node_ptr_ = static_cast<str_rng_node_ptr>(binary_node<T>::branch_[0].first);
 
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == range)
                   return;
 
                str0_range_ptr_ = &(range->range_ref());
             }
 
             if (is_generally_string_node(binary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == range)
                   return;
 
                str1_range_ptr_ = &(range->range_ref());
             }
 
             initialised_ = str0_base_ptr_     &&
                            str1_base_ptr_     &&
                            str0_rng_node_ptr_ &&
                            str0_range_ptr_    &&
                            str1_range_ptr_    ;
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                std::size_t s0_r0 = 0;
                std::size_t s0_r1 = 0;
 
                std::size_t s1_r0 = 0;
                std::size_t s1_r1 = 0;
 
a65c8e8b
                const range_t& range0 = (*str0_range_ptr_);
                const range_t& range1 = (*str1_range_ptr_);
4068375e
 
                if (
                     range0(s0_r0, s0_r1, str0_base_ptr_->size()) &&
                     range1(s1_r0, s1_r1, str1_base_ptr_->size())
                   )
                {
                   const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1;
 
                   std::copy(str1_base_ptr_->base() + s1_r0,
                             str1_base_ptr_->base() + s1_r0 + size,
                             const_cast<char_ptr>(base() + s0_r0));
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return str0_base_ptr_->str();
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return str0_base_ptr_->base();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return str0_base_ptr_->size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return str0_rng_node_ptr_->range_ref();
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return str0_rng_node_ptr_->range_ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strass;
          }
 
       private:
 
          bool             initialised_;
          str_base_ptr     str0_base_ptr_;
          str_base_ptr     str1_base_ptr_;
          str_rng_node_ptr str0_rng_node_ptr_;
          range_ptr        str0_range_ptr_;
          range_ptr        str1_range_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class conditional_string_node exprtk_final
                                     : public trinary_node    <T>,
4068375e
                                       public string_base_node<T>,
                                       public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface <T>  irange_t;
          typedef irange_t*            irange_ptr;
4068375e
          typedef expression_node <T>* expression_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
a65c8e8b
          conditional_string_node(expression_ptr condition,
4068375e
                                  expression_ptr consequent,
                                  expression_ptr alternative)
a65c8e8b
          : trinary_node<T>(details::e_default, consequent, alternative, condition)
          , initialised_(false)
          , str0_base_ptr_ (0)
          , str1_base_ptr_ (0)
          , str0_range_ptr_(0)
          , str1_range_ptr_(0)
          , condition_  (condition  )
          , consequent_ (consequent )
          , alternative_(alternative)
4068375e
          {
             range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
 
             range_.cache.first  = range_.n0_c.second;
             range_.cache.second = range_.n1_c.second;
 
             if (is_generally_string_node(trinary_node<T>::branch_[0].first))
             {
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(trinary_node<T>::branch_[0].first);
 
                if (0 == str0_base_ptr_)
                   return;
 
                str0_range_ptr_ = dynamic_cast<irange_ptr>(trinary_node<T>::branch_[0].first);
 
                if (0 == str0_range_ptr_)
                   return;
             }
 
             if (is_generally_string_node(trinary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(trinary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                str1_range_ptr_ = dynamic_cast<irange_ptr>(trinary_node<T>::branch_[1].first);
 
                if (0 == str1_range_ptr_)
                   return;
             }
 
             initialised_ = str0_base_ptr_  &&
                            str1_base_ptr_  &&
                            str0_range_ptr_ &&
                            str1_range_ptr_ ;
 
a65c8e8b
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(condition_  );
                assert(consequent_ );
                assert(alternative_);
 
4068375e
                std::size_t r0 = 0;
                std::size_t r1 = 0;
 
a65c8e8b
                if (is_true(condition_))
4068375e
                {
                   consequent_->value();
 
a65c8e8b
                   const range_t& range = str0_range_ptr_->range_ref();
4068375e
 
                   if (range(r0, r1, str0_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
                      value_.assign(str0_base_ptr_->base() + r0, size);
 
                      range_.n1_c.second  = value_.size() - 1;
                      range_.cache.second = range_.n1_c.second;
 
                      return T(1);
                   }
                }
                else
                {
                   alternative_->value();
 
a65c8e8b
                   const range_t& range = str1_range_ptr_->range_ref();
4068375e
 
                   if (range(r0, r1, str1_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
                      value_.assign(str1_base_ptr_->base() + r0, size);
 
                      range_.n1_c.second  = value_.size() - 1;
                      range_.cache.second = range_.n1_c.second;
 
                      return T(0);
                   }
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return value_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return &value_[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return value_.size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strcondition;
          }
 
       private:
 
          bool initialised_;
          str_base_ptr str0_base_ptr_;
          str_base_ptr str1_base_ptr_;
          irange_ptr   str0_range_ptr_;
          irange_ptr   str1_range_ptr_;
          mutable range_t     range_;
          mutable std::string value_;
 
a65c8e8b
          expression_ptr condition_;
4068375e
          expression_ptr consequent_;
          expression_ptr alternative_;
       };
 
       template <typename T>
a65c8e8b
       class cons_conditional_str_node exprtk_final
                                       : public binary_node     <T>,
4068375e
                                         public string_base_node<T>,
                                         public range_interface <T>
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface <T>  irange_t;
          typedef irange_t*            irange_ptr;
4068375e
          typedef expression_node <T>* expression_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
4068375e
 
a65c8e8b
          cons_conditional_str_node(expression_ptr condition,
4068375e
                                    expression_ptr consequent)
a65c8e8b
          : binary_node<T>(details::e_default, consequent, condition)
          , initialised_(false)
          , str0_base_ptr_ (0)
          , str0_range_ptr_(0)
          , condition_ (condition )
          , consequent_(consequent)
4068375e
          {
             range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
 
             range_.cache.first  = range_.n0_c.second;
             range_.cache.second = range_.n1_c.second;
 
             if (is_generally_string_node(binary_node<T>::branch_[0].first))
             {
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_base_ptr_)
                   return;
 
                str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_range_ptr_)
                   return;
             }
 
             initialised_ = str0_base_ptr_ && str0_range_ptr_ ;
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(condition_ );
                assert(consequent_);
 
                if (is_true(condition_))
4068375e
                {
                   consequent_->value();
 
a65c8e8b
                   const range_t& range = str0_range_ptr_->range_ref();
4068375e
 
                   std::size_t r0 = 0;
                   std::size_t r1 = 0;
 
                   if (range(r0, r1, str0_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
                      value_.assign(str0_base_ptr_->base() + r0, size);
 
                      range_.n1_c.second  = value_.size() - 1;
                      range_.cache.second = range_.n1_c.second;
 
                      return T(1);
                   }
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
          std::string str() const
          {
             return value_;
          }
 
          char_cptr base() const
          {
             return &value_[0];
          }
 
          std::size_t size() const
          {
             return value_.size();
          }
 
          range_t& range_ref()
          {
             return range_;
          }
 
          const range_t& range_ref() const
          {
             return range_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strccondition;
          }
 
       private:
 
          bool initialised_;
          str_base_ptr str0_base_ptr_;
          irange_ptr   str0_range_ptr_;
          mutable range_t     range_;
          mutable std::string value_;
 
a65c8e8b
          expression_ptr condition_;
4068375e
          expression_ptr consequent_;
       };
 
       template <typename T, typename VarArgFunction>
a65c8e8b
       class str_vararg_node exprtk_final
                             : public expression_node <T>,
                               public string_base_node<T>,
                               public range_interface <T>
4068375e
       {
       public:
 
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
          typedef range_t*             range_ptr;
          typedef range_interface <T>  irange_t;
          typedef irange_t*            irange_ptr;
          typedef expression_node <T>* expression_ptr;
          typedef string_base_node<T>* str_base_ptr;
4068375e
          typedef std::pair<expression_ptr,bool> branch_t;
 
          template <typename Allocator,
                    template <typename, typename> class Sequence>
          explicit str_vararg_node(const Sequence<expression_ptr,Allocator>& arg_list)
a65c8e8b
          : initialised_(false)
          , str_base_ptr_ (0)
          , str_range_ptr_(0)
4068375e
          {
             construct_branch_pair(final_node_, const_cast<expression_ptr>(arg_list.back()));
 
             if (0 == final_node_.first)
                return;
             else if (!is_generally_string_node(final_node_.first))
                return;
 
             str_base_ptr_ = dynamic_cast<str_base_ptr>(final_node_.first);
 
             if (0 == str_base_ptr_)
                return;
 
             str_range_ptr_ = dynamic_cast<irange_ptr>(final_node_.first);
 
             if (0 == str_range_ptr_)
                return;
 
             initialised_ = str_base_ptr_  && str_range_ptr_;
 
             if (arg_list.size() > 1)
             {
                const std::size_t arg_list_size = arg_list.size() - 1;
 
                arg_list_.resize(arg_list_size);
 
                for (std::size_t i = 0; i < arg_list_size; ++i)
                {
                   if (arg_list[i])
                   {
                      construct_branch_pair(arg_list_[i], arg_list[i]);
                   }
                   else
                   {
                      arg_list_.clear();
                      return;
                   }
                }
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (!arg_list_.empty())
             {
                VarArgFunction::process(arg_list_);
             }
 
             final_node_.first->value();
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return str_base_ptr_->str();
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
             return str_base_ptr_->base();
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return str_base_ptr_->size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return str_range_ptr_->range_ref();
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return str_range_ptr_->range_ref();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_stringvararg;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
a65c8e8b
             expression_node<T>::ndb_t::collect(final_node_ , node_delete_list);
             expression_node<T>::ndb_t::collect(arg_list_   , node_delete_list);
4068375e
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return std::max(
                expression_node<T>::ndb_t::compute_node_depth(final_node_),
                expression_node<T>::ndb_t::compute_node_depth(arg_list_  ));
          }
 
       private:
 
          bool                  initialised_;
          branch_t              final_node_;
          str_base_ptr          str_base_ptr_;
          irange_ptr            str_range_ptr_;
          std::vector<branch_t> arg_list_;
       };
       #endif
 
       template <typename T, std::size_t N>
a65c8e8b
       inline T axn(const T a, const T x)
4068375e
       {
          // a*x^n
          return a * exprtk::details::numeric::fast_exp<T,N>::result(x);
       }
 
       template <typename T, std::size_t N>
a65c8e8b
       inline T axnb(const T a, const T x, const T b)
4068375e
       {
          // a*x^n+b
          return a * exprtk::details::numeric::fast_exp<T,N>::result(x) + b;
       }
 
       template <typename T>
       struct sf_base
       {
          typedef typename details::functor_t<T>::Type Type;
          typedef typename details::functor_t<T> functor_t;
          typedef typename functor_t::qfunc_t quaternary_functor_t;
a65c8e8b
          typedef typename functor_t::tfunc_t trinary_functor_t;
          typedef typename functor_t::bfunc_t binary_functor_t;
          typedef typename functor_t::ufunc_t unary_functor_t;
4068375e
       };
 
a65c8e8b
       #define define_sfop3(NN, OP0, OP1)                 \
4068375e
       template <typename T>                              \
       struct sf##NN##_op : public sf_base<T>             \
       {                                                  \
          typedef typename sf_base<T>::Type const Type;   \
          static inline T process(Type x, Type y, Type z) \
          {                                               \
             return (OP0);                                \
          }                                               \
          static inline std::string id()                  \
          {                                               \
             return (OP1);                                \
          }                                               \
       };                                                 \
 
       define_sfop3(00,(x + y) / z       ,"(t+t)/t")
       define_sfop3(01,(x + y) * z       ,"(t+t)*t")
       define_sfop3(02,(x + y) - z       ,"(t+t)-t")
       define_sfop3(03,(x + y) + z       ,"(t+t)+t")
       define_sfop3(04,(x - y) + z       ,"(t-t)+t")
       define_sfop3(05,(x - y) / z       ,"(t-t)/t")
       define_sfop3(06,(x - y) * z       ,"(t-t)*t")
       define_sfop3(07,(x * y) + z       ,"(t*t)+t")
       define_sfop3(08,(x * y) - z       ,"(t*t)-t")
       define_sfop3(09,(x * y) / z       ,"(t*t)/t")
       define_sfop3(10,(x * y) * z       ,"(t*t)*t")
       define_sfop3(11,(x / y) + z       ,"(t/t)+t")
       define_sfop3(12,(x / y) - z       ,"(t/t)-t")
       define_sfop3(13,(x / y) / z       ,"(t/t)/t")
       define_sfop3(14,(x / y) * z       ,"(t/t)*t")
       define_sfop3(15,x / (y + z)       ,"t/(t+t)")
       define_sfop3(16,x / (y - z)       ,"t/(t-t)")
       define_sfop3(17,x / (y * z)       ,"t/(t*t)")
       define_sfop3(18,x / (y / z)       ,"t/(t/t)")
       define_sfop3(19,x * (y + z)       ,"t*(t+t)")
       define_sfop3(20,x * (y - z)       ,"t*(t-t)")
       define_sfop3(21,x * (y * z)       ,"t*(t*t)")
       define_sfop3(22,x * (y / z)       ,"t*(t/t)")
       define_sfop3(23,x - (y + z)       ,"t-(t+t)")
       define_sfop3(24,x - (y - z)       ,"t-(t-t)")
       define_sfop3(25,x - (y / z)       ,"t-(t/t)")
       define_sfop3(26,x - (y * z)       ,"t-(t*t)")
       define_sfop3(27,x + (y * z)       ,"t+(t*t)")
       define_sfop3(28,x + (y / z)       ,"t+(t/t)")
       define_sfop3(29,x + (y + z)       ,"t+(t+t)")
       define_sfop3(30,x + (y - z)       ,"t+(t-t)")
       define_sfop3(31,(axnb<T,2>(x,y,z)),"       ")
       define_sfop3(32,(axnb<T,3>(x,y,z)),"       ")
       define_sfop3(33,(axnb<T,4>(x,y,z)),"       ")
       define_sfop3(34,(axnb<T,5>(x,y,z)),"       ")
       define_sfop3(35,(axnb<T,6>(x,y,z)),"       ")
       define_sfop3(36,(axnb<T,7>(x,y,z)),"       ")
       define_sfop3(37,(axnb<T,8>(x,y,z)),"       ")
       define_sfop3(38,(axnb<T,9>(x,y,z)),"       ")
       define_sfop3(39,x * numeric::log(y)   + z,"")
       define_sfop3(40,x * numeric::log(y)   - z,"")
       define_sfop3(41,x * numeric::log10(y) + z,"")
       define_sfop3(42,x * numeric::log10(y) - z,"")
       define_sfop3(43,x * numeric::sin(y) + z  ,"")
       define_sfop3(44,x * numeric::sin(y) - z  ,"")
       define_sfop3(45,x * numeric::cos(y) + z  ,"")
       define_sfop3(46,x * numeric::cos(y) - z  ,"")
       define_sfop3(47,details::is_true(x) ? y : z,"")
 
a65c8e8b
       #define define_sfop4(NN, OP0, OP1)                         \
4068375e
       template <typename T>                                      \
       struct sf##NN##_op : public sf_base<T>                     \
       {                                                          \
          typedef typename sf_base<T>::Type const Type;           \
          static inline T process(Type x, Type y, Type z, Type w) \
          {                                                       \
             return (OP0);                                        \
          }                                                       \
          static inline std::string id()                          \
          {                                                       \
             return (OP1);                                        \
          }                                                       \
       };                                                         \
 
       define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)")
       define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)")
       define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)")
       define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)")
       define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)")
       define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)")
       define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)")
       define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)")
       define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)")
       define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)")
       define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)")
       define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)")
       define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)")
       define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)")
       define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)")
       define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)")
       define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)")
       define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t")
       define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t")
       define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t")
       define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t")
       define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t")
       define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t")
       define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t")
       define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t")
       define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)")
       define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)")
       define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)")
       define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)")
       define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)")
       define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)")
       define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)")
       define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))")
       define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))")
       define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))")
       define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))")
 
       define_sfop4(84,(axn<T,2>(x,y) + axn<T,2>(z,w)),"")
       define_sfop4(85,(axn<T,3>(x,y) + axn<T,3>(z,w)),"")
       define_sfop4(86,(axn<T,4>(x,y) + axn<T,4>(z,w)),"")
       define_sfop4(87,(axn<T,5>(x,y) + axn<T,5>(z,w)),"")
       define_sfop4(88,(axn<T,6>(x,y) + axn<T,6>(z,w)),"")
       define_sfop4(89,(axn<T,7>(x,y) + axn<T,7>(z,w)),"")
       define_sfop4(90,(axn<T,8>(x,y) + axn<T,8>(z,w)),"")
       define_sfop4(91,(axn<T,9>(x,y) + axn<T,9>(z,w)),"")
       define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"")
       define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"")
       define_sfop4(94,((x <  y) ? z : w),"")
       define_sfop4(95,((x <= y) ? z : w),"")
       define_sfop4(96,((x >  y) ? z : w),"")
       define_sfop4(97,((x >= y) ? z : w),"")
       define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"")
       define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"")
 
       define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)")
       define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)")
       define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)")
       define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)")
       define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)")
       define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)")
       define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)")
       define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)")
       define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)")
       define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)")
       define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)")
       define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)")
       define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)")
       define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)")
       define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)")
       define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)")
       define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)")
       define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)")
       define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)")
       define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)")
       define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)")
       define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)")
       define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)")
       define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)")
       define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)")
       define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)")
       define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)")
       define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)")
       define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)")
       define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)")
       define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)")
       define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)")
       define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)")
       define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)")
       define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)")
       define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)")
       define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)")
       define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)")
       define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)")
       define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)")
       define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)")
       define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)")
       define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)")
       define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)")
       define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))")
       define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))")
       define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))")
       define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))")
       define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t")
       define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t")
       define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t")
       define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t")
       define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t")
       define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t")
       define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)")
       define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)")
       define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)")
       define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)")
       define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)")
       define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)")
       define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)")
       define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t")
 
       #undef define_sfop3
       #undef define_sfop4
 
       template <typename T, typename SpecialFunction>
a65c8e8b
       class sf3_node exprtk_final : public trinary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          sf3_node(const operator_type& opr,
                   expression_ptr branch0,
                   expression_ptr branch1,
                   expression_ptr branch2)
          : trinary_node<T>(opr, branch0, branch1, branch2)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(trinary_node<T>::branch_[0].first);
             assert(trinary_node<T>::branch_[1].first);
             assert(trinary_node<T>::branch_[2].first);
 
4068375e
             const T x = trinary_node<T>::branch_[0].first->value();
             const T y = trinary_node<T>::branch_[1].first->value();
             const T z = trinary_node<T>::branch_[2].first->value();
 
             return SpecialFunction::process(x, y, z);
          }
       };
 
       template <typename T, typename SpecialFunction>
a65c8e8b
       class sf4_node exprtk_final : public quaternary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          sf4_node(const operator_type& opr,
                   expression_ptr branch0,
                   expression_ptr branch1,
                   expression_ptr branch2,
                   expression_ptr branch3)
          : quaternary_node<T>(opr, branch0, branch1, branch2, branch3)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(quaternary_node<T>::branch_[0].first);
             assert(quaternary_node<T>::branch_[1].first);
             assert(quaternary_node<T>::branch_[2].first);
             assert(quaternary_node<T>::branch_[3].first);
 
4068375e
             const T x = quaternary_node<T>::branch_[0].first->value();
             const T y = quaternary_node<T>::branch_[1].first->value();
             const T z = quaternary_node<T>::branch_[2].first->value();
             const T w = quaternary_node<T>::branch_[3].first->value();
 
             return SpecialFunction::process(x, y, z, w);
          }
       };
 
       template <typename T, typename SpecialFunction>
a65c8e8b
       class sf3_var_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          sf3_var_node(const T& v0, const T& v1, const T& v2)
a65c8e8b
          : v0_(v0)
          , v1_(v1)
          , v2_(v2)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return SpecialFunction::process(v0_, v1_, v2_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_trinary;
          }
 
       private:
 
a65c8e8b
          sf3_var_node(const sf3_var_node<T,SpecialFunction>&) exprtk_delete;
          sf3_var_node<T,SpecialFunction>& operator=(const sf3_var_node<T,SpecialFunction>&) exprtk_delete;
4068375e
 
          const T& v0_;
          const T& v1_;
          const T& v2_;
       };
 
       template <typename T, typename SpecialFunction>
a65c8e8b
       class sf4_var_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3)
a65c8e8b
          : v0_(v0)
          , v1_(v1)
          , v2_(v2)
          , v3_(v3)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return SpecialFunction::process(v0_, v1_, v2_, v3_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_trinary;
          }
 
       private:
 
a65c8e8b
          sf4_var_node(const sf4_var_node<T,SpecialFunction>&) exprtk_delete;
          sf4_var_node<T,SpecialFunction>& operator=(const sf4_var_node<T,SpecialFunction>&) exprtk_delete;
4068375e
 
          const T& v0_;
          const T& v1_;
          const T& v2_;
          const T& v3_;
       };
 
       template <typename T, typename VarArgFunction>
a65c8e8b
       class vararg_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          template <typename Allocator,
                    template <typename, typename> class Sequence>
          explicit vararg_node(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             arg_list_.resize(arg_list.size());
 
             for (std::size_t i = 0; i < arg_list.size(); ++i)
             {
                if (arg_list[i])
                {
                   construct_branch_pair(arg_list_[i],arg_list[i]);
                }
                else
                {
                   arg_list_.clear();
                   return;
                }
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return VarArgFunction::process(arg_list_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vararg;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(arg_list_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
 
       private:
 
          std::vector<branch_t> arg_list_;
       };
 
       template <typename T, typename VarArgFunction>
a65c8e8b
       class vararg_varnode exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
                    template <typename, typename> class Sequence>
          explicit vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             arg_list_.resize(arg_list.size());
 
             for (std::size_t i = 0; i < arg_list.size(); ++i)
             {
                if (arg_list[i] && is_variable_node(arg_list[i]))
                {
                   variable_node<T>* var_node_ptr = static_cast<variable_node<T>*>(arg_list[i]);
                   arg_list_[i] = (&var_node_ptr->ref());
                }
                else
                {
                   arg_list_.clear();
                   return;
                }
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (!arg_list_.empty())
                return VarArgFunction::process(arg_list_);
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vararg;
          }
 
       private:
 
          std::vector<const T*> arg_list_;
       };
 
       template <typename T, typename VecFunction>
a65c8e8b
       class vectorize_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          explicit vectorize_node(const expression_ptr v)
          : ivec_ptr_(0)
          {
             construct_branch_pair(v_, v);
 
             if (is_ivector_node(v_.first))
             {
                ivec_ptr_ = dynamic_cast<vector_interface<T>*>(v_.first);
             }
             else
                ivec_ptr_ = 0;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (ivec_ptr_)
             {
a65c8e8b
                assert(v_.first);
 
4068375e
                v_.first->value();
a65c8e8b
 
4068375e
                return VecFunction::process(ivec_ptr_);
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecfunc;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(v_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(v_);
          }
 
       private:
 
          vector_interface<T>* ivec_ptr_;
          branch_t                    v_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_node(const operator_type& opr,
                          expression_ptr branch0,
                          expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , var_node_ptr_(0)
4068375e
          {
             if (is_variable_node(binary_node<T>::branch_[0].first))
             {
                var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (var_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& result = var_node_ptr_->ref();
 
                result = binary_node<T>::branch_[1].first->value();
 
                return result;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          variable_node<T>* var_node_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_vec_elem_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_vec_elem_node(const operator_type& opr,
                                   expression_ptr branch0,
                                   expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec_node_ptr_(0)
4068375e
          {
             if (is_vector_elem_node(binary_node<T>::branch_[0].first))
             {
                vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& result = vec_node_ptr_->ref();
 
                result = binary_node<T>::branch_[1].first->value();
 
                return result;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          vector_elem_node<T>* vec_node_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_rebasevec_elem_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_rebasevec_elem_node(const operator_type& opr,
                                         expression_ptr branch0,
                                         expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , rbvec_node_ptr_(0)
4068375e
          {
             if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first))
             {
                rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (rbvec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& result = rbvec_node_ptr_->ref();
 
                result = binary_node<T>::branch_[1].first->value();
 
                return result;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          rebasevector_elem_node<T>* rbvec_node_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_rebasevec_celem_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_rebasevec_celem_node(const operator_type& opr,
                                          expression_ptr branch0,
                                          expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , rbvec_node_ptr_(0)
4068375e
          {
             if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first))
             {
                rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (rbvec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& result = rbvec_node_ptr_->ref();
 
                result = binary_node<T>::branch_[1].first->value();
 
                return result;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          rebasevector_celem_node<T>* rbvec_node_ptr_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_vec_node exprtk_final
                                 : public binary_node     <T>
                                 , public vector_interface<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
a65c8e8b
          typedef vector_node<T>*     vector_node_ptr;
          typedef vec_data_store<T>   vds_t;
4068375e
 
          assignment_vec_node(const operator_type& opr,
                              expression_ptr branch0,
                              expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec_node_ptr_(0)
4068375e
          {
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
                vds()         = vec_node_ptr_->vds();
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                const T v = binary_node<T>::branch_[1].first->value();
 
                T* vec = vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec + lud.upper_bound;
 
                while (vec < upper_bound)
                {
                   #define exprtk_loop(N) \
                   vec[N] = v;            \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec += lud.batch_size;
                }
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N) \
                   case N : *vec++ = v; \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return vec_node_ptr_->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return vec_node_ptr_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return vec_node_ptr_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvalass;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node<T>* vec_node_ptr_;
          vds_t           vds_;
       };
 
       template <typename T>
a65c8e8b
       class assignment_vecvec_node exprtk_final
                                    : public binary_node     <T>
                                    , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
4068375e
          typedef vector_node<T>*     vector_node_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          assignment_vecvec_node(const operator_type& opr,
                                 expression_ptr branch0,
                                 expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec0_node_ptr_(0)
          , vec1_node_ptr_(0)
          , initialised_(false)
          , src_is_ivec_(false)
4068375e
          {
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
                vds()          = vec0_node_ptr_->vds();
             }
 
             if (is_vector_node(binary_node<T>::branch_[1].first))
             {
                vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first);
                vds_t::match_sizes(vds(),vec1_node_ptr_->vds());
             }
             else if (is_ivector_node(binary_node<T>::branch_[1].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
                {
                   vec1_node_ptr_ = vi->vec();
 
                   if (!vi->side_effect())
                   {
                      vi->vds()    = vds();
                      src_is_ivec_ = true;
                   }
                   else
                      vds_t::match_sizes(vds(),vi->vds());
                }
             }
 
             initialised_ = (vec0_node_ptr_ && vec1_node_ptr_);
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[1].first->value();
 
                if (src_is_ivec_)
                   return vec0_node_ptr_->value();
 
                T* vec0 = vec0_node_ptr_->vds().data();
                T* vec1 = vec1_node_ptr_->vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec0 + lud.upper_bound;
 
                while (vec0 < upper_bound)
                {
                   #define exprtk_loop(N) \
                   vec0[N] = vec1[N];     \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                }
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)        \
                   case N : *vec0++ = *vec1++; \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return vec0_node_ptr_->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvecass;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node<T>* vec0_node_ptr_;
          vector_node<T>* vec1_node_ptr_;
          bool            initialised_;
          bool            src_is_ivec_;
          vds_t           vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_op_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_op_node(const operator_type& opr,
                             expression_ptr branch0,
                             expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , var_node_ptr_(0)
4068375e
          {
             if (is_variable_node(binary_node<T>::branch_[0].first))
             {
                var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (var_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& v = var_node_ptr_->ref();
                v = Operation::process(v,binary_node<T>::branch_[1].first->value());
 
                return v;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          variable_node<T>* var_node_ptr_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_vec_elem_op_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_vec_elem_op_node(const operator_type& opr,
                                      expression_ptr branch0,
                                      expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec_node_ptr_(0)
4068375e
          {
             if (is_vector_elem_node(binary_node<T>::branch_[0].first))
             {
                vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& v = vec_node_ptr_->ref();
                   v = Operation::process(v,binary_node<T>::branch_[1].first->value());
 
                return v;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          vector_elem_node<T>* vec_node_ptr_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_rebasevec_elem_op_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_rebasevec_elem_op_node(const operator_type& opr,
                                            expression_ptr branch0,
                                            expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , rbvec_node_ptr_(0)
4068375e
          {
             if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first))
             {
                rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (rbvec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& v = rbvec_node_ptr_->ref();
                   v = Operation::process(v,binary_node<T>::branch_[1].first->value());
 
                return v;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          rebasevector_elem_node<T>* rbvec_node_ptr_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_rebasevec_celem_op_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          assignment_rebasevec_celem_op_node(const operator_type& opr,
                                             expression_ptr branch0,
                                             expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , rbvec_node_ptr_(0)
4068375e
          {
             if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first))
             {
                rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first);
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (rbvec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                T& v = rbvec_node_ptr_->ref();
                   v = Operation::process(v,binary_node<T>::branch_[1].first->value());
 
                return v;
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
       private:
 
          rebasevector_celem_node<T>* rbvec_node_ptr_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_vec_op_node exprtk_final
                                    : public binary_node     <T>
                                    , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
4068375e
          typedef vector_node<T>*     vector_node_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          assignment_vec_op_node(const operator_type& opr,
                                 expression_ptr branch0,
                                 expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec_node_ptr_(0)
4068375e
          {
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
                vds()         = vec_node_ptr_->vds();
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                const T v = binary_node<T>::branch_[1].first->value();
 
                T* vec = vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec + lud.upper_bound;
 
                while (vec < upper_bound)
                {
                   #define exprtk_loop(N)       \
                   Operation::assign(vec[N],v); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec += lud.batch_size;
                }
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                  \
                   case N : Operation::assign(*vec++,v); \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return vec_node_ptr_->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return vec_node_ptr_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return vec_node_ptr_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecopvalass;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          bool side_effect() const exprtk_override
4068375e
          {
             return true;
          }
 
       private:
 
          vector_node<T>* vec_node_ptr_;
          vds_t           vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class assignment_vecvec_op_node exprtk_final
                                       : public binary_node     <T>
                                       , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
4068375e
          typedef vector_node<T>*     vector_node_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          assignment_vecvec_op_node(const operator_type& opr,
                                    expression_ptr branch0,
                                    expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec0_node_ptr_(0)
          , vec1_node_ptr_(0)
          , initialised_(false)
4068375e
          {
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
                vds()          = vec0_node_ptr_->vds();
             }
 
             if (is_vector_node(binary_node<T>::branch_[1].first))
             {
                vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first);
                vec1_node_ptr_->vds() = vds();
             }
             else if (is_ivector_node(binary_node<T>::branch_[1].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
                {
                   vec1_node_ptr_ = vi->vec();
                   vec1_node_ptr_->vds() = vds();
                }
                else
                   vds_t::match_sizes(vds(),vec1_node_ptr_->vds());
             }
 
             initialised_ = (vec0_node_ptr_ && vec1_node_ptr_);
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                      T* vec0 = vec0_node_ptr_->vds().data();
                const T* vec1 = vec1_node_ptr_->vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec0 + lud.upper_bound;
 
                while (vec0 < upper_bound)
                {
                   #define exprtk_loop(N)                          \
                   vec0[N] = Operation::process(vec0[N], vec1[N]); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                }
 
                int i = 0;
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                                              \
                   case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return vec0_node_ptr_->value();
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return vec0_node_ptr_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecopvecass;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          bool side_effect() const exprtk_override
4068375e
          {
             return true;
          }
 
       private:
 
          vector_node<T>* vec0_node_ptr_;
          vector_node<T>* vec1_node_ptr_;
          bool            initialised_;
          vds_t           vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class vec_binop_vecvec_node exprtk_final
                                   : public binary_node     <T>
                                   , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
          typedef vector_node<T>*     vector_node_ptr;
4068375e
          typedef vector_holder<T>*   vector_holder_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          vec_binop_vecvec_node(const operator_type& opr,
                                expression_ptr branch0,
                                expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec0_node_ptr_(0)
          , vec1_node_ptr_(0)
          , temp_         (0)
          , temp_vec_node_(0)
          , initialised_(false)
4068375e
          {
             bool v0_is_ivec = false;
             bool v1_is_ivec = false;
 
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first);
             }
             else if (is_ivector_node(binary_node<T>::branch_[0].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
                {
                   vec0_node_ptr_ = vi->vec();
                   v0_is_ivec     = true;
                }
             }
 
             if (is_vector_node(binary_node<T>::branch_[1].first))
             {
                vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first);
             }
             else if (is_ivector_node(binary_node<T>::branch_[1].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
                {
                   vec1_node_ptr_ = vi->vec();
                   v1_is_ivec     = true;
                }
             }
 
             if (vec0_node_ptr_ && vec1_node_ptr_)
             {
                vector_holder<T>& vec0 = vec0_node_ptr_->vec_holder();
                vector_holder<T>& vec1 = vec1_node_ptr_->vec_holder();
 
                if (v0_is_ivec && (vec0.size() <= vec1.size()))
                   vds_ = vds_t(vec0_node_ptr_->vds());
                else if (v1_is_ivec && (vec1.size() <= vec0.size()))
                   vds_ = vds_t(vec1_node_ptr_->vds());
                else
                   vds_ = vds_t(std::min(vec0.size(),vec1.size()));
 
                temp_          = new vector_holder<T>(vds().data(),vds().size());
a65c8e8b
                temp_vec_node_ = new vector_node  <T>(vds(),temp_);
4068375e
 
                initialised_ = true;
             }
a65c8e8b
 
             assert(initialised_);
4068375e
          }
 
         ~vec_binop_vecvec_node()
          {
             delete temp_;
             delete temp_vec_node_;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (initialised_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                const T* vec0 = vec0_node_ptr_->vds().data();
                const T* vec1 = vec1_node_ptr_->vds().data();
                      T* vec2 = vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec2 + lud.upper_bound;
 
                while (vec2 < upper_bound)
                {
                   #define exprtk_loop(N)                          \
                   vec2[N] = Operation::process(vec0[N], vec1[N]); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                   vec2 += lud.batch_size;
                }
 
                int i = 0;
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                                              \
                   case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return (vds().data())[0];
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvecarith;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds_.size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node_ptr   vec0_node_ptr_;
          vector_node_ptr   vec1_node_ptr_;
          vector_holder_ptr temp_;
          vector_node_ptr   temp_vec_node_;
          bool              initialised_;
          vds_t             vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class vec_binop_vecval_node exprtk_final
                                   : public binary_node     <T>
                                   , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
          typedef vector_node<T>*     vector_node_ptr;
4068375e
          typedef vector_holder<T>*   vector_holder_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          vec_binop_vecval_node(const operator_type& opr,
                                expression_ptr branch0,
                                expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec0_node_ptr_(0)
          , temp_         (0)
          , temp_vec_node_(0)
4068375e
          {
             bool v0_is_ivec = false;
 
             if (is_vector_node(binary_node<T>::branch_[0].first))
             {
                vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first);
             }
             else if (is_ivector_node(binary_node<T>::branch_[0].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
                {
                   vec0_node_ptr_ = vi->vec();
                   v0_is_ivec     = true;
                }
             }
 
             if (vec0_node_ptr_)
             {
                if (v0_is_ivec)
                   vds() = vec0_node_ptr_->vds();
                else
                   vds() = vds_t(vec0_node_ptr_->size());
 
                temp_          = new vector_holder<T>(vds());
a65c8e8b
                temp_vec_node_ = new vector_node  <T>(vds(),temp_);
4068375e
             }
          }
 
         ~vec_binop_vecval_node()
          {
             delete temp_;
             delete temp_vec_node_;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec0_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                            binary_node<T>::branch_[0].first->value();
                const T v = binary_node<T>::branch_[1].first->value();
 
                const T* vec0 = vec0_node_ptr_->vds().data();
                      T* vec1 = vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec0 + lud.upper_bound;
 
                while (vec0 < upper_bound)
                {
                   #define exprtk_loop(N)                    \
                   vec1[N] = Operation::process(vec0[N], v); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                }
 
                int i = 0;
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                                        \
                   case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return (vds().data())[0];
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvalarith;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node_ptr   vec0_node_ptr_;
          vector_holder_ptr temp_;
          vector_node_ptr   temp_vec_node_;
          vds_t             vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class vec_binop_valvec_node exprtk_final
                                   : public binary_node     <T>
                                   , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
          typedef vector_node<T>*     vector_node_ptr;
4068375e
          typedef vector_holder<T>*   vector_holder_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          vec_binop_valvec_node(const operator_type& opr,
                                expression_ptr branch0,
                                expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , vec1_node_ptr_(0)
          , temp_         (0)
          , temp_vec_node_(0)
4068375e
          {
             bool v1_is_ivec = false;
 
             if (is_vector_node(binary_node<T>::branch_[1].first))
             {
                vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first);
             }
             else if (is_ivector_node(binary_node<T>::branch_[1].first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
                {
                   vec1_node_ptr_ = vi->vec();
                   v1_is_ivec     = true;
                }
             }
 
             if (vec1_node_ptr_)
             {
                if (v1_is_ivec)
                   vds() = vec1_node_ptr_->vds();
                else
                   vds() = vds_t(vec1_node_ptr_->size());
 
                temp_          = new vector_holder<T>(vds());
a65c8e8b
                temp_vec_node_ = new vector_node  <T>(vds(),temp_);
4068375e
             }
          }
 
         ~vec_binop_valvec_node()
          {
             delete temp_;
             delete temp_vec_node_;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (vec1_node_ptr_)
             {
a65c8e8b
                assert(binary_node<T>::branch_[0].first);
                assert(binary_node<T>::branch_[1].first);
 
4068375e
                const T v = binary_node<T>::branch_[0].first->value();
                            binary_node<T>::branch_[1].first->value();
 
                      T* vec0 = vds().data();
                const T* vec1 = vec1_node_ptr_->vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec0 + lud.upper_bound;
 
                while (vec0 < upper_bound)
                {
                   #define exprtk_loop(N)                    \
                   vec0[N] = Operation::process(v, vec1[N]); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                }
 
                int i = 0;
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                                        \
                   case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return (vds().data())[0];
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecvalarith;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node_ptr   vec1_node_ptr_;
          vector_holder_ptr temp_;
          vector_node_ptr   temp_vec_node_;
          vds_t             vds_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class unary_vector_node exprtk_final
                               : public unary_node      <T>
                               , public vector_interface<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef expression_node<T>* expression_ptr;
          typedef vector_node<T>*     vector_node_ptr;
4068375e
          typedef vector_holder<T>*   vector_holder_ptr;
a65c8e8b
          typedef vec_data_store<T>   vds_t;
4068375e
 
          unary_vector_node(const operator_type& opr, expression_ptr branch0)
a65c8e8b
          : unary_node<T>(opr, branch0)
          , vec0_node_ptr_(0)
          , temp_         (0)
          , temp_vec_node_(0)
4068375e
          {
             bool vec0_is_ivec = false;
 
             if (is_vector_node(unary_node<T>::branch_.first))
             {
                vec0_node_ptr_ = static_cast<vector_node_ptr>(unary_node<T>::branch_.first);
             }
             else if (is_ivector_node(unary_node<T>::branch_.first))
             {
                vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                if (0 != (vi = dynamic_cast<vector_interface<T>*>(unary_node<T>::branch_.first)))
                {
                   vec0_node_ptr_ = vi->vec();
                   vec0_is_ivec   = true;
                }
             }
 
             if (vec0_node_ptr_)
             {
                if (vec0_is_ivec)
                   vds_ = vec0_node_ptr_->vds();
                else
                   vds_ = vds_t(vec0_node_ptr_->size());
 
                temp_          = new vector_holder<T>(vds());
a65c8e8b
                temp_vec_node_ = new vector_node  <T>(vds(),temp_);
4068375e
             }
          }
 
         ~unary_vector_node()
          {
             delete temp_;
             delete temp_vec_node_;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(unary_node<T>::branch_.first);
 
4068375e
             unary_node<T>::branch_.first->value();
 
             if (vec0_node_ptr_)
             {
                const T* vec0 = vec0_node_ptr_->vds().data();
                      T* vec1 = vds().data();
 
                loop_unroll::details lud(size());
                const T* upper_bound = vec0 + lud.upper_bound;
 
                while (vec0 < upper_bound)
                {
                   #define exprtk_loop(N)                 \
                   vec1[N] = Operation::process(vec0[N]); \
 
                   exprtk_loop( 0) exprtk_loop( 1)
                   exprtk_loop( 2) exprtk_loop( 3)
                   #ifndef exprtk_disable_superscalar_unroll
                   exprtk_loop( 4) exprtk_loop( 5)
                   exprtk_loop( 6) exprtk_loop( 7)
                   exprtk_loop( 8) exprtk_loop( 9)
                   exprtk_loop(10) exprtk_loop(11)
                   exprtk_loop(12) exprtk_loop(13)
                   exprtk_loop(14) exprtk_loop(15)
                   #endif
 
                   vec0 += lud.batch_size;
                   vec1 += lud.batch_size;
                }
 
                int i = 0;
 
                exprtk_disable_fallthrough_begin
                switch (lud.remainder)
                {
                   #define case_stmt(N)                                     \
                   case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(15) case_stmt(14)
                   case_stmt(13) case_stmt(12)
                   case_stmt(11) case_stmt(10)
                   case_stmt( 9) case_stmt( 8)
                   case_stmt( 7) case_stmt( 6)
                   case_stmt( 5) case_stmt( 4)
                   #endif
                   case_stmt( 3) case_stmt( 2)
                   case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef exprtk_loop
                #undef case_stmt
 
                return (vds().data())[0];
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          vector_node_ptr vec() const exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          vector_node_ptr vec() exprtk_override
4068375e
          {
             return temp_vec_node_;
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vecunaryop;
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return vds().size();
          }
 
a65c8e8b
          vds_t& vds() exprtk_override
4068375e
          {
             return vds_;
          }
 
a65c8e8b
          const vds_t& vds() const exprtk_override
4068375e
          {
             return vds_;
          }
 
       private:
 
          vector_node_ptr   vec0_node_ptr_;
          vector_holder_ptr temp_;
          vector_node_ptr   temp_vec_node_;
          vds_t             vds_;
       };
 
       template <typename T>
a65c8e8b
       class conditional_vector_node exprtk_final
                                     : public expression_node <T>
                                     , public vector_interface<T>
       {
       public:
 
          typedef expression_node <T>* expression_ptr;
          typedef vector_interface<T>* vec_interface_ptr;
          typedef vector_node     <T>* vector_node_ptr;
          typedef vector_holder   <T>* vector_holder_ptr;
          typedef vec_data_store  <T>  vds_t;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          conditional_vector_node(expression_ptr condition,
                                  expression_ptr consequent,
                                  expression_ptr alternative)
          : consequent_node_ptr_ (0)
          , alternative_node_ptr_(0)
          , temp_vec_node_       (0)
          , temp_                (0)
          , vec_size_            (0)
          , initialised_         (false)
          {
             construct_branch_pair(condition_  , condition  );
             construct_branch_pair(consequent_ , consequent );
             construct_branch_pair(alternative_, alternative);
 
             if (details::is_ivector_node(consequent_.first))
             {
                vec_interface_ptr ivec_ptr = dynamic_cast<vec_interface_ptr>(consequent_.first);
 
                if (0 != ivec_ptr)
                {
                   consequent_node_ptr_ = ivec_ptr->vec();
                }
             }
 
             if (details::is_ivector_node(alternative_.first))
             {
                vec_interface_ptr ivec_ptr = dynamic_cast<vec_interface_ptr>(alternative_.first);
 
                if (0 != ivec_ptr)
                {
                   alternative_node_ptr_ = ivec_ptr->vec();
                }
             }
 
             if (consequent_node_ptr_ && alternative_node_ptr_)
             {
                vec_size_ = std::min(consequent_node_ptr_ ->vds().size(),
                                     alternative_node_ptr_->vds().size());
 
                vds_           = vds_t(vec_size_);
                temp_          = new vector_holder<T>(vds_);
                temp_vec_node_ = new vector_node  <T>(vds(),temp_);
 
                initialised_ = true;
             }
 
             assert(initialised_ && (vec_size_ > 0));
          }
 
         ~conditional_vector_node()
          {
             delete temp_;
             delete temp_vec_node_;
          }
 
          inline T value() const exprtk_override
          {
             if (initialised_)
             {
                assert(condition_  .first);
                assert(consequent_ .first);
                assert(alternative_.first);
 
                T result = T(0);
                T* source_vector = 0;
                T* result_vector = vds().data();
 
                if (is_true(condition_))
                {
                   result        = consequent_.first->value();
                   source_vector = consequent_node_ptr_->vds().data();
                }
                else
                {
                   result        = alternative_.first->value();
                   source_vector = alternative_node_ptr_->vds().data();
                }
 
                for (std::size_t i = 0; i < vec_size_; ++i)
                {
                   result_vector[i] = source_vector[i];
                }
 
                return result;
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
          vector_node_ptr vec() const exprtk_override
          {
             return temp_vec_node_;
          }
 
          vector_node_ptr vec() exprtk_override
          {
             return temp_vec_node_;
          }
 
          inline typename expression_node<T>::node_type type() const exprtk_override
          {
             return expression_node<T>::e_vecondition;
          }
 
          std::size_t size() const exprtk_override
          {
             return vec_size_;
          }
 
          vds_t& vds() exprtk_override
          {
             return vds_;
          }
 
          const vds_t& vds() const exprtk_override
          {
             return vds_;
          }
 
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
          {
             expression_node<T>::ndb_t::collect(condition_   , node_delete_list);
             expression_node<T>::ndb_t::collect(consequent_  , node_delete_list);
             expression_node<T>::ndb_t::collect(alternative_ , node_delete_list);
          }
 
          std::size_t node_depth() const exprtk_override
          {
             return expression_node<T>::ndb_t::compute_node_depth
                (condition_, consequent_, alternative_);
          }
 
       private:
 
          branch_t condition_;
          branch_t consequent_;
          branch_t alternative_;
          vector_node_ptr   consequent_node_ptr_;
          vector_node_ptr   alternative_node_ptr_;
          vector_node_ptr   temp_vec_node_;
          vector_holder_ptr temp_;
          vds_t vds_;
          std::size_t vec_size_;
          bool        initialised_;
       };
 
       template <typename T>
       class scand_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          scand_node(const operator_type& opr,
                     expression_ptr branch0,
                     expression_ptr branch1)
          : binary_node<T>(opr, branch0, branch1)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(binary_node<T>::branch_[0].first);
             assert(binary_node<T>::branch_[1].first);
 
4068375e
             return (
                      std::not_equal_to<T>()
                         (T(0),binary_node<T>::branch_[0].first->value()) &&
                      std::not_equal_to<T>()
                         (T(0),binary_node<T>::branch_[1].first->value())
                    ) ? T(1) : T(0);
          }
       };
 
       template <typename T>
a65c8e8b
       class scor_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          scor_node(const operator_type& opr,
                    expression_ptr branch0,
                    expression_ptr branch1)
          : binary_node<T>(opr, branch0, branch1)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(binary_node<T>::branch_[0].first);
             assert(binary_node<T>::branch_[1].first);
 
4068375e
             return (
                      std::not_equal_to<T>()
                         (T(0),binary_node<T>::branch_[0].first->value()) ||
                      std::not_equal_to<T>()
                         (T(0),binary_node<T>::branch_[1].first->value())
                    ) ? T(1) : T(0);
          }
       };
 
       template <typename T, typename IFunction, std::size_t N>
a65c8e8b
       class function_N_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          // Function of N paramters.
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef IFunction ifunction;
 
          explicit function_N_node(ifunction* func)
a65c8e8b
          : function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0))
          , parameter_count_(func->param_count)
4068375e
          {}
 
          template <std::size_t NumBranches>
          bool init_branches(expression_ptr (&b)[NumBranches])
          {
             // Needed for incompetent and broken msvc compiler versions
             #ifdef _MSC_VER
              #pragma warning(push)
              #pragma warning(disable: 4127)
             #endif
             if (N != NumBranches)
                return false;
             else
             {
                for (std::size_t i = 0; i < NumBranches; ++i)
                {
                   if (b[i])
                      branch_[i] = std::make_pair(b[i],branch_deletable(b[i]));
                   else
                      return false;
                }
                return true;
             }
             #ifdef _MSC_VER
              #pragma warning(pop)
             #endif
          }
 
          inline bool operator <(const function_N_node<T,IFunction,N>& fn) const
          {
             return this < (&fn);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             // Needed for incompetent and broken msvc compiler versions
             #ifdef _MSC_VER
              #pragma warning(push)
              #pragma warning(disable: 4127)
             #endif
             if ((0 == function_) || (0 == N))
                return std::numeric_limits<T>::quiet_NaN();
             else
             {
                T v[N];
                evaluate_branches<T,N>::execute(v,branch_);
                return invoke<T,N>::execute(*function_,v);
             }
             #ifdef _MSC_VER
              #pragma warning(pop)
             #endif
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
          {
             return expression_node<T>::e_function;
          }
 
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
          std::size_t node_depth() const exprtk_override
          {
             return expression_node<T>::ndb_t::template compute_node_depth<N>(branch_);
          }
 
4068375e
          template <typename T_, std::size_t BranchCount>
          struct evaluate_branches
          {
             static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount])
             {
                for (std::size_t i = 0; i < BranchCount; ++i)
                {
                   v[i] = b[i].first->value();
                }
             }
          };
 
          template <typename T_>
          struct evaluate_branches <T_,5>
          {
             static inline void execute(T_ (&v)[5], const branch_t (&b)[5])
             {
                v[0] = b[0].first->value();
                v[1] = b[1].first->value();
                v[2] = b[2].first->value();
                v[3] = b[3].first->value();
                v[4] = b[4].first->value();
             }
          };
 
          template <typename T_>
          struct evaluate_branches <T_,4>
          {
             static inline void execute(T_ (&v)[4], const branch_t (&b)[4])
             {
                v[0] = b[0].first->value();
                v[1] = b[1].first->value();
                v[2] = b[2].first->value();
                v[3] = b[3].first->value();
             }
          };
 
          template <typename T_>
          struct evaluate_branches <T_,3>
          {
             static inline void execute(T_ (&v)[3], const branch_t (&b)[3])
             {
                v[0] = b[0].first->value();
                v[1] = b[1].first->value();
                v[2] = b[2].first->value();
             }
          };
 
          template <typename T_>
          struct evaluate_branches <T_,2>
          {
             static inline void execute(T_ (&v)[2], const branch_t (&b)[2])
             {
                v[0] = b[0].first->value();
                v[1] = b[1].first->value();
             }
          };
 
          template <typename T_>
          struct evaluate_branches <T_,1>
          {
             static inline void execute(T_ (&v)[1], const branch_t (&b)[1])
             {
                v[0] = b[0].first->value();
             }
          };
 
          template <typename T_, std::size_t ParamCount>
          struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits<T_>::quiet_NaN(); } };
 
          template <typename T_>
          struct invoke<T_,20>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[20])
             { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); }
          };
 
          template <typename T_>
          struct invoke<T_,19>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[19])
             { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); }
          };
 
          template <typename T_>
          struct invoke<T_,18>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[18])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,17>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[17])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,16>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[16])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,15>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[15])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,14>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[14])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,13>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[13])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,12>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[12])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,11>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[11])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,10>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[10])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,9>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[9])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,8>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[8])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,7>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[7])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,6>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[6])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4], v[5]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,5>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[5])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3], v[4]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,4>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[4])
a65c8e8b
             { return f(v[0], v[1], v[2], v[3]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,3>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[3])
a65c8e8b
             { return f(v[0], v[1], v[2]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,2>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[2])
a65c8e8b
             { return f(v[0], v[1]); }
4068375e
          };
 
          template <typename T_>
          struct invoke<T_,1>
          {
             static inline T_ execute(ifunction& f, T_ (&v)[1])
             { return f(v[0]); }
          };
 
       private:
 
          ifunction*  function_;
          std::size_t parameter_count_;
          branch_t    branch_[N];
       };
 
       template <typename T, typename IFunction>
a65c8e8b
       class function_N_node<T,IFunction,0> exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef IFunction ifunction;
 
          explicit function_N_node(ifunction* func)
          : function_((0 == func->param_count) ? func : reinterpret_cast<ifunction*>(0))
          {}
 
          inline bool operator <(const function_N_node<T,IFunction,0>& fn) const
          {
             return this < (&fn);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (function_)
                return (*function_)();
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_function;
          }
 
       private:
 
          ifunction* function_;
       };
 
       template <typename T, typename VarArgFunction>
a65c8e8b
       class vararg_function_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
 
          vararg_function_node(VarArgFunction*  func,
                               const std::vector<expression_ptr>& arg_list)
a65c8e8b
          : function_(func)
          , arg_list_(arg_list)
4068375e
          {
             value_list_.resize(arg_list.size(),std::numeric_limits<T>::quiet_NaN());
          }
 
          inline bool operator <(const vararg_function_node<T,VarArgFunction>& fn) const
          {
             return this < (&fn);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (function_)
             {
                populate_value_list();
                return (*function_)(value_list_);
             }
             else
                return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_vafunction;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             for (std::size_t i = 0; i < arg_list_.size(); ++i)
             {
                if (arg_list_[i] && !details::is_variable_node(arg_list_[i]))
                {
                   node_delete_list.push_back(&arg_list_[i]);
                }
             }
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(arg_list_);
          }
 
       private:
 
          inline void populate_value_list() const
          {
             for (std::size_t i = 0; i < arg_list_.size(); ++i)
             {
                value_list_[i] = arg_list_[i]->value();
             }
          }
 
          VarArgFunction* function_;
          std::vector<expression_ptr> arg_list_;
          mutable std::vector<T> value_list_;
       };
 
       template <typename T, typename GenericFunction>
       class generic_function_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          typedef type_store<T>       type_store_t;
          typedef expression_node<T>* expression_ptr;
          typedef variable_node<T>    variable_node_t;
          typedef vector_node<T>      vector_node_t;
          typedef variable_node_t*    variable_node_ptr_t;
          typedef vector_node_t*      vector_node_ptr_t;
          typedef range_interface<T>  range_interface_t;
          typedef range_data_type<T>  range_data_type_t;
          typedef typename range_interface<T>::range_t range_t;
 
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef std::pair<void*,std::size_t>   void_t;
 
          typedef std::vector<T>                 tmp_vs_t;
          typedef std::vector<type_store_t>      typestore_list_t;
          typedef std::vector<range_data_type_t> range_list_t;
4068375e
 
          explicit generic_function_node(const std::vector<expression_ptr>& arg_list,
a65c8e8b
                                         GenericFunction* func = reinterpret_cast<GenericFunction*>(0))
          : function_(func)
          , arg_list_(arg_list)
4068375e
          {}
 
a65c8e8b
          virtual ~generic_function_node() {}
4068375e
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
          virtual bool init_branches()
          {
             expr_as_vec1_store_.resize(arg_list_.size(),T(0)               );
             typestore_list_    .resize(arg_list_.size(),type_store_t()     );
             range_list_        .resize(arg_list_.size(),range_data_type_t());
a65c8e8b
             branch_            .resize(arg_list_.size(),branch_t(reinterpret_cast<expression_ptr>(0),false));
4068375e
 
             for (std::size_t i = 0; i < arg_list_.size(); ++i)
             {
                type_store_t& ts = typestore_list_[i];
 
                if (0 == arg_list_[i])
                   return false;
                else if (is_ivector_node(arg_list_[i]))
                {
                   vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
 
                   if (0 == (vi = dynamic_cast<vector_interface<T>*>(arg_list_[i])))
                      return false;
 
                   ts.size = vi->size();
                   ts.data = vi->vds().data();
                   ts.type = type_store_t::e_vector;
                   vi->vec()->vec_holder().set_ref(&ts.vec_data);
                }
                #ifndef exprtk_disable_string_capabilities
                else if (is_generally_string_node(arg_list_[i]))
                {
                   string_base_node<T>* sbn = reinterpret_cast<string_base_node<T>*>(0);
 
                   if (0 == (sbn = dynamic_cast<string_base_node<T>*>(arg_list_[i])))
                      return false;
 
                   ts.size = sbn->size();
                   ts.data = reinterpret_cast<void*>(const_cast<char_ptr>(sbn->base()));
                   ts.type = type_store_t::e_string;
 
                   range_list_[i].data      = ts.data;
                   range_list_[i].size      = ts.size;
                   range_list_[i].type_size = sizeof(char);
                   range_list_[i].str_node  = sbn;
 
                   range_interface_t* ri = reinterpret_cast<range_interface_t*>(0);
 
                   if (0 == (ri = dynamic_cast<range_interface_t*>(arg_list_[i])))
                      return false;
 
a65c8e8b
                   const range_t& rp = ri->range_ref();
4068375e
 
                   if (
                        rp.const_range() &&
                        is_const_string_range_node(arg_list_[i])
                      )
                   {
                      ts.size = rp.const_size();
                      ts.data = static_cast<char_ptr>(ts.data) + rp.n0_c.second;
                      range_list_[i].range = reinterpret_cast<range_t*>(0);
                   }
                   else
                      range_list_[i].range = &(ri->range_ref());
                }
                #endif
                else if (is_variable_node(arg_list_[i]))
                {
                   variable_node_ptr_t var = variable_node_ptr_t(0);
 
                   if (0 == (var = dynamic_cast<variable_node_ptr_t>(arg_list_[i])))
                      return false;
 
                   ts.size = 1;
                   ts.data = &var->ref();
                   ts.type = type_store_t::e_scalar;
                }
                else
                {
                   ts.size = 1;
                   ts.data = reinterpret_cast<void*>(&expr_as_vec1_store_[i]);
                   ts.type = type_store_t::e_scalar;
                }
 
                branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i]));
             }
 
             return true;
          }
 
          inline bool operator <(const generic_function_node<T,GenericFunction>& fn) const
          {
             return this < (&fn);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (function_)
             {
                if (populate_value_list())
                {
                   typedef typename GenericFunction::parameter_list_t parameter_list_t;
 
                   return (*function_)(parameter_list_t(typestore_list_));
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_genfunction;
          }
 
       protected:
 
          inline virtual bool populate_value_list() const
          {
             for (std::size_t i = 0; i < branch_.size(); ++i)
             {
                expr_as_vec1_store_[i] = branch_[i].first->value();
             }
 
             for (std::size_t i = 0; i < branch_.size(); ++i)
             {
                range_data_type_t& rdt = range_list_[i];
 
                if (rdt.range)
                {
a65c8e8b
                   const range_t& rp = (*rdt.range);
                   std::size_t r0    = 0;
                   std::size_t r1    = 0;
4068375e
 
a65c8e8b
                   if (rp(r0, r1, rdt.size))
4068375e
                   {
                      type_store_t& ts = typestore_list_[i];
 
                      ts.size = rp.cache_size();
                      #ifndef exprtk_disable_string_capabilities
                      if (ts.type == type_store_t::e_string)
                         ts.data = const_cast<char_ptr>(rdt.str_node->base()) + rp.cache.first;
                      else
                      #endif
                         ts.data = static_cast<char_ptr>(rdt.data) + (rp.cache.first * rdt.type_size);
                   }
                   else
                      return false;
                }
             }
 
             return true;
          }
 
          GenericFunction* function_;
          mutable typestore_list_t typestore_list_;
 
       private:
 
          std::vector<expression_ptr> arg_list_;
          std::vector<branch_t>         branch_;
          mutable tmp_vs_t  expr_as_vec1_store_;
          mutable range_list_t      range_list_;
       };
 
       #ifndef exprtk_disable_string_capabilities
       template <typename T, typename StringFunction>
       class string_function_node : public generic_function_node<T,StringFunction>,
                                    public string_base_node<T>,
                                    public range_interface <T>
       {
       public:
 
          typedef generic_function_node<T,StringFunction> gen_function_t;
a65c8e8b
          typedef typename range_interface<T>::range_t range_t;
4068375e
 
          string_function_node(StringFunction* func,
                               const std::vector<typename gen_function_t::expression_ptr>& arg_list)
          : gen_function_t(arg_list,func)
          {
             range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
             range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
             range_.cache.first  = range_.n0_c.second;
             range_.cache.second = range_.n1_c.second;
          }
 
          inline bool operator <(const string_function_node<T,StringFunction>& fn) const
          {
             return this < (&fn);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (gen_function_t::function_)
             {
                if (gen_function_t::populate_value_list())
                {
                   typedef typename StringFunction::parameter_list_t parameter_list_t;
 
                   const T result = (*gen_function_t::function_)
                                       (
                                         ret_string_,
                                         parameter_list_t(gen_function_t::typestore_list_)
                                       );
 
                   range_.n1_c.second  = ret_string_.size() - 1;
                   range_.cache.second = range_.n1_c.second;
 
                   return result;
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strfunction;
          }
 
a65c8e8b
          std::string str() const exprtk_override
4068375e
          {
             return ret_string_;
          }
 
a65c8e8b
          char_cptr base() const exprtk_override
4068375e
          {
            return &ret_string_[0];
          }
 
a65c8e8b
          std::size_t size() const exprtk_override
4068375e
          {
             return ret_string_.size();
          }
 
a65c8e8b
          range_t& range_ref() exprtk_override
4068375e
          {
             return range_;
          }
 
a65c8e8b
          const range_t& range_ref() const exprtk_override
4068375e
          {
             return range_;
          }
 
       protected:
 
          mutable range_t     range_;
          mutable std::string ret_string_;
       };
       #endif
 
       template <typename T, typename GenericFunction>
       class multimode_genfunction_node : public generic_function_node<T,GenericFunction>
       {
       public:
 
          typedef generic_function_node<T,GenericFunction> gen_function_t;
a65c8e8b
          typedef typename gen_function_t::range_t         range_t;
4068375e
 
          multimode_genfunction_node(GenericFunction* func,
                                     const std::size_t& param_seq_index,
                                     const std::vector<typename gen_function_t::expression_ptr>& arg_list)
a65c8e8b
          : gen_function_t(arg_list,func)
          , param_seq_index_(param_seq_index)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (gen_function_t::function_)
             {
                if (gen_function_t::populate_value_list())
                {
                   typedef typename GenericFunction::parameter_list_t parameter_list_t;
 
                   return (*gen_function_t::function_)
                             (
                               param_seq_index_,
                               parameter_list_t(gen_function_t::typestore_list_)
                             );
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override exprtk_final
4068375e
          {
             return expression_node<T>::e_genfunction;
          }
 
       private:
 
          std::size_t param_seq_index_;
       };
 
       #ifndef exprtk_disable_string_capabilities
       template <typename T, typename StringFunction>
a65c8e8b
       class multimode_strfunction_node exprtk_final : public string_function_node<T,StringFunction>
4068375e
       {
       public:
 
          typedef string_function_node<T,StringFunction> str_function_t;
a65c8e8b
          typedef typename str_function_t::range_t range_t;
4068375e
 
          multimode_strfunction_node(StringFunction* func,
                                     const std::size_t& param_seq_index,
                                     const std::vector<typename str_function_t::expression_ptr>& arg_list)
a65c8e8b
          : str_function_t(func,arg_list)
          , param_seq_index_(param_seq_index)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (str_function_t::function_)
             {
                if (str_function_t::populate_value_list())
                {
                   typedef typename StringFunction::parameter_list_t parameter_list_t;
 
                   const T result = (*str_function_t::function_)
                                       (
                                         param_seq_index_,
                                         str_function_t::ret_string_,
                                         parameter_list_t(str_function_t::typestore_list_)
                                       );
 
                   str_function_t::range_.n1_c.second  = str_function_t::ret_string_.size() - 1;
                   str_function_t::range_.cache.second = str_function_t::range_.n1_c.second;
 
                   return result;
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_strfunction;
          }
 
       private:
 
          const std::size_t param_seq_index_;
       };
       #endif
 
       class return_exception
       {};
 
       template <typename T>
       class null_igenfunc
       {
       public:
 
a65c8e8b
          virtual ~null_igenfunc() {}
4068375e
 
          typedef type_store<T> generic_type;
          typedef typename generic_type::parameter_list parameter_list_t;
 
          inline virtual T operator() (parameter_list_t)
          {
             return std::numeric_limits<T>::quiet_NaN();
          }
       };
 
       #ifndef exprtk_disable_return_statement
       template <typename T>
a65c8e8b
       class return_node exprtk_final : public generic_function_node<T,null_igenfunc<T> >
4068375e
       {
       public:
 
a65c8e8b
          typedef results_context<T>   results_context_t;
          typedef null_igenfunc<T>     igeneric_function_t;
4068375e
          typedef igeneric_function_t* igeneric_function_ptr;
          typedef generic_function_node<T,igeneric_function_t> gen_function_t;
 
          return_node(const std::vector<typename gen_function_t::expression_ptr>& arg_list,
                      results_context_t& rc)
a65c8e8b
          : gen_function_t  (arg_list)
          , results_context_(&rc)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (
                  (0 != results_context_) &&
                  gen_function_t::populate_value_list()
                )
             {
                typedef typename type_store<T>::parameter_list parameter_list_t;
 
                results_context_->
                   assign(parameter_list_t(gen_function_t::typestore_list_));
 
                throw return_exception();
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_return;
          }
 
       private:
 
          results_context_t* results_context_;
       };
 
       template <typename T>
a65c8e8b
       class return_envelope_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef results_context<T>  results_context_t;
          typedef std::pair<expression_ptr,bool> branch_t;
 
          return_envelope_node(expression_ptr body, results_context_t& rc)
a65c8e8b
          : results_context_(&rc  )
          , return_invoked_ (false)
4068375e
          {
             construct_branch_pair(body_, body);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(body_.first);
 
4068375e
             try
             {
                return_invoked_ = false;
                results_context_->clear();
 
                return body_.first->value();
             }
             catch(const return_exception&)
             {
                return_invoked_ = true;
                return std::numeric_limits<T>::quiet_NaN();
             }
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_retenv;
          }
 
          inline bool* retinvk_ptr()
          {
             return &return_invoked_;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(body_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(body_);
          }
 
       private:
 
          results_context_t* results_context_;
          mutable bool        return_invoked_;
          branch_t                      body_;
       };
       #endif
 
       #define exprtk_define_unary_op(OpName)                    \
       template <typename T>                                     \
       struct OpName##_op                                        \
       {                                                         \
          typedef typename functor_t<T>::Type Type;              \
          typedef typename expression_node<T>::node_type node_t; \
                                                                 \
          static inline T process(Type v)                        \
          {                                                      \
             return numeric:: OpName (v);                        \
          }                                                      \
                                                                 \
          static inline node_t type()                            \
          {                                                      \
             return expression_node<T>::e_##OpName;              \
          }                                                      \
                                                                 \
          static inline details::operator_type operation()       \
          {                                                      \
             return details::e_##OpName;                         \
          }                                                      \
       };                                                        \
 
       exprtk_define_unary_op(abs  )
       exprtk_define_unary_op(acos )
       exprtk_define_unary_op(acosh)
       exprtk_define_unary_op(asin )
       exprtk_define_unary_op(asinh)
       exprtk_define_unary_op(atan )
       exprtk_define_unary_op(atanh)
       exprtk_define_unary_op(ceil )
       exprtk_define_unary_op(cos  )
       exprtk_define_unary_op(cosh )
       exprtk_define_unary_op(cot  )
       exprtk_define_unary_op(csc  )
       exprtk_define_unary_op(d2g  )
       exprtk_define_unary_op(d2r  )
       exprtk_define_unary_op(erf  )
       exprtk_define_unary_op(erfc )
       exprtk_define_unary_op(exp  )
       exprtk_define_unary_op(expm1)
       exprtk_define_unary_op(floor)
       exprtk_define_unary_op(frac )
       exprtk_define_unary_op(g2d  )
       exprtk_define_unary_op(log  )
       exprtk_define_unary_op(log10)
       exprtk_define_unary_op(log2 )
       exprtk_define_unary_op(log1p)
       exprtk_define_unary_op(ncdf )
       exprtk_define_unary_op(neg  )
       exprtk_define_unary_op(notl )
       exprtk_define_unary_op(pos  )
       exprtk_define_unary_op(r2d  )
       exprtk_define_unary_op(round)
       exprtk_define_unary_op(sec  )
       exprtk_define_unary_op(sgn  )
       exprtk_define_unary_op(sin  )
       exprtk_define_unary_op(sinc )
       exprtk_define_unary_op(sinh )
       exprtk_define_unary_op(sqrt )
       exprtk_define_unary_op(tan  )
       exprtk_define_unary_op(tanh )
       exprtk_define_unary_op(trunc)
       #undef exprtk_define_unary_op
 
       template <typename T>
       struct opr_base
       {
          typedef typename details::functor_t<T>::Type    Type;
          typedef typename details::functor_t<T>::RefType RefType;
a65c8e8b
          typedef typename details::functor_t<T> functor_t;
          typedef typename functor_t::qfunc_t    quaternary_functor_t;
          typedef typename functor_t::tfunc_t    trinary_functor_t;
          typedef typename functor_t::bfunc_t    binary_functor_t;
          typedef typename functor_t::ufunc_t    unary_functor_t;
4068375e
       };
 
       template <typename T>
       struct add_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return t1 + t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; }
          static inline void assign(RefType t1, Type t2) { t1 += t2; }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_add; }
          static inline details::operator_type operation() { return details::e_add; }
       };
 
       template <typename T>
       struct mul_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return t1 * t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; }
          static inline void assign(RefType t1, Type t2) { t1 *= t2; }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mul; }
          static inline details::operator_type operation() { return details::e_mul; }
       };
 
       template <typename T>
       struct sub_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return t1 - t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; }
          static inline void assign(RefType t1, Type t2) { t1 -= t2; }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_sub; }
          static inline details::operator_type operation() { return details::e_sub; }
       };
 
       template <typename T>
       struct div_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return t1 / t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; }
          static inline void assign(RefType t1, Type t2) { t1 /= t2; }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_div; }
          static inline details::operator_type operation() { return details::e_div; }
       };
 
       template <typename T>
       struct mod_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return numeric::modulus<T>(t1,t2); }
          static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mod; }
          static inline details::operator_type operation() { return details::e_mod; }
       };
 
       template <typename T>
       struct pow_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
 
          static inline T process(Type t1, Type t2) { return numeric::pow<T>(t1,t2); }
          static inline void assign(RefType t1, Type t2) { t1 = numeric::pow<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_pow; }
          static inline details::operator_type operation() { return details::e_pow; }
       };
 
       template <typename T>
       struct lt_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lt; }
          static inline details::operator_type operation() { return details::e_lt; }
       };
 
       template <typename T>
       struct lte_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lte; }
          static inline details::operator_type operation() { return details::e_lte; }
       };
 
       template <typename T>
       struct gt_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gt; }
          static inline details::operator_type operation() { return details::e_gt; }
       };
 
       template <typename T>
       struct gte_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gte; }
          static inline details::operator_type operation() { return details::e_gte; }
       };
 
       template <typename T>
       struct eq_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
          static inline T process(Type t1, Type t2) { return (std::equal_to<T>()(t1,t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_eq; }
          static inline details::operator_type operation() { return details::e_eq; }
       };
 
       template <typename T>
       struct equal_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_eq; }
          static inline details::operator_type operation() { return details::e_equal; }
       };
 
       template <typename T>
       struct ne_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return (std::not_equal_to<T>()(t1,t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ne; }
          static inline details::operator_type operation() { return details::e_ne; }
       };
 
       template <typename T>
       struct and_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_and; }
          static inline details::operator_type operation() { return details::e_and; }
       };
 
       template <typename T>
       struct nand_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nand; }
          static inline details::operator_type operation() { return details::e_nand; }
       };
 
       template <typename T>
       struct or_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_or; }
          static inline details::operator_type operation() { return details::e_or; }
       };
 
       template <typename T>
       struct nor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_nor; }
       };
 
       template <typename T>
       struct xor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return numeric::xor_opr<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_xor; }
       };
 
       template <typename T>
       struct xnor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(Type t1, Type t2) { return numeric::xnor_opr<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_xnor; }
       };
 
       template <typename T>
       struct in_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_in; }
          static inline details::operator_type operation() { return details::e_in; }
       };
 
       template <typename T>
       struct like_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_like; }
          static inline details::operator_type operation() { return details::e_like; }
       };
 
       template <typename T>
       struct ilike_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ilike; }
          static inline details::operator_type operation() { return details::e_ilike; }
       };
 
       template <typename T>
       struct inrange_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); }
          static inline T process(const std::string& t0, const std::string& t1, const std::string& t2)
          {
             return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0);
          }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_inranges; }
          static inline details::operator_type operation() { return details::e_inrange; }
       };
 
       template <typename T>
       inline T value(details::expression_node<T>* n)
       {
          return n->value();
       }
 
       template <typename T>
       inline T value(std::pair<details::expression_node<T>*,bool> n)
       {
          return n.first->value();
       }
 
       template <typename T>
       inline T value(const T* t)
       {
          return (*t);
       }
 
       template <typename T>
       inline T value(const T& t)
       {
          return t;
       }
 
       template <typename T>
       struct vararg_add_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return T(0);
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             T result = T(0);
 
                             for (std::size_t i = 0; i < arg_list.size(); ++i)
                             {
                               result += value(arg_list[i]);
                             }
 
                             return result;
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]) +
                    value(arg_list[2]) ;
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]) +
                    value(arg_list[2]) + value(arg_list[3]) ;
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]) +
                    value(arg_list[2]) + value(arg_list[3]) +
                    value(arg_list[4]) ;
          }
       };
 
       template <typename T>
       struct vararg_mul_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return T(0);
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             T result = T(value(arg_list[0]));
 
                             for (std::size_t i = 1; i < arg_list.size(); ++i)
                             {
                                result *= value(arg_list[i]);
                             }
 
                             return result;
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]) *
                    value(arg_list[2]) ;
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]) *
                    value(arg_list[2]) * value(arg_list[3]) ;
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]) *
                    value(arg_list[2]) * value(arg_list[3]) *
                    value(arg_list[4]) ;
          }
       };
 
       template <typename T>
       struct vararg_avg_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return T(0);
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default : return vararg_add_op<T>::process(arg_list) / arg_list.size();
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return (value(arg_list[0]) + value(arg_list[1])) / T(2);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3);
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return (value(arg_list[0]) + value(arg_list[1]) +
                     value(arg_list[2]) + value(arg_list[3])) / T(4);
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return (value(arg_list[0]) + value(arg_list[1]) +
                     value(arg_list[2]) + value(arg_list[3]) +
                     value(arg_list[4])) / T(5);
          }
       };
 
       template <typename T>
       struct vararg_min_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return T(0);
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             T result = T(value(arg_list[0]));
 
                             for (std::size_t i = 1; i < arg_list.size(); ++i)
                             {
                                const T v = value(arg_list[i]);
 
                                if (v < result)
                                   result = v;
                             }
 
                             return result;
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return std::min<T>(value(arg_list[0]),value(arg_list[1]));
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return std::min<T>(std::min<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2]));
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return std::min<T>(
                         std::min<T>(value(arg_list[0]), value(arg_list[1])),
                         std::min<T>(value(arg_list[2]), value(arg_list[3])));
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return std::min<T>(
                    std::min<T>(std::min<T>(value(arg_list[0]), value(arg_list[1])),
                                std::min<T>(value(arg_list[2]), value(arg_list[3]))),
                                value(arg_list[4]));
          }
       };
 
       template <typename T>
       struct vararg_max_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return T(0);
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             T result = T(value(arg_list[0]));
 
                             for (std::size_t i = 1; i < arg_list.size(); ++i)
                             {
                                const T v = value(arg_list[i]);
 
                                if (v > result)
                                   result = v;
                             }
 
                             return result;
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return std::max<T>(value(arg_list[0]),value(arg_list[1]));
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return std::max<T>(std::max<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2]));
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return std::max<T>(
                         std::max<T>(value(arg_list[0]), value(arg_list[1])),
                         std::max<T>(value(arg_list[2]), value(arg_list[3])));
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return std::max<T>(
                    std::max<T>(std::max<T>(value(arg_list[0]), value(arg_list[1])),
                                std::max<T>(value(arg_list[2]), value(arg_list[3]))),
                                value(arg_list[4]));
          }
       };
 
       template <typename T>
       struct vararg_mand_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             for (std::size_t i = 0; i < arg_list.size(); ++i)
                             {
                                if (std::equal_to<T>()(T(0), value(arg_list[i])))
                                   return T(0);
                             }
 
                             return T(1);
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return std::not_equal_to<T>()
                       (T(0), value(arg_list[0])) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[1]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[2]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[2])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[3]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[2])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[3])) &&
                      std::not_equal_to<T>()(T(0), value(arg_list[4]))
                    ) ? T(1) : T(0);
          }
       };
 
       template <typename T>
       struct vararg_mor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                default :
                          {
                             for (std::size_t i = 0; i < arg_list.size(); ++i)
                             {
                                if (std::not_equal_to<T>()(T(0), value(arg_list[i])))
                                   return T(1);
                             }
 
                             return T(0);
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return std::not_equal_to<T>()
                       (T(0), value(arg_list[0])) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[1]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[2]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[2])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[3]))
                    ) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
             return (
                      std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[2])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[3])) ||
                      std::not_equal_to<T>()(T(0), value(arg_list[4]))
                    ) ? T(1) : T(0);
          }
       };
 
       template <typename T>
       struct vararg_multi_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
 
          template <typename Type,
                    typename Allocator,
                    template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
             {
                case 0  : return std::numeric_limits<T>::quiet_NaN();
                case 1  : return process_1(arg_list);
                case 2  : return process_2(arg_list);
                case 3  : return process_3(arg_list);
                case 4  : return process_4(arg_list);
                case 5  : return process_5(arg_list);
                case 6  : return process_6(arg_list);
                case 7  : return process_7(arg_list);
                case 8  : return process_8(arg_list);
                default :
                          {
                             for (std::size_t i = 0; i < (arg_list.size() - 1); ++i)
                             {
                                value(arg_list[i]);
                             }
 
                             return value(arg_list.back());
                          }
             }
          }
 
          template <typename Sequence>
          static inline T process_1(const Sequence& arg_list)
          {
             return value(arg_list[0]);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
                    value(arg_list[0]);
             return value(arg_list[1]);
          }
 
          template <typename Sequence>
          static inline T process_3(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
             return value(arg_list[2]);
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
                    value(arg_list[2]);
             return value(arg_list[3]);
          }
 
          template <typename Sequence>
          static inline T process_5(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
                    value(arg_list[2]);
                    value(arg_list[3]);
             return value(arg_list[4]);
          }
 
          template <typename Sequence>
          static inline T process_6(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
                    value(arg_list[2]);
                    value(arg_list[3]);
                    value(arg_list[4]);
             return value(arg_list[5]);
          }
 
          template <typename Sequence>
          static inline T process_7(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
                    value(arg_list[2]);
                    value(arg_list[3]);
                    value(arg_list[4]);
                    value(arg_list[5]);
             return value(arg_list[6]);
          }
 
          template <typename Sequence>
          static inline T process_8(const Sequence& arg_list)
          {
                    value(arg_list[0]);
                    value(arg_list[1]);
                    value(arg_list[2]);
                    value(arg_list[3]);
                    value(arg_list[4]);
                    value(arg_list[5]);
                    value(arg_list[6]);
             return value(arg_list[7]);
          }
       };
 
       template <typename T>
       struct vec_add_op
       {
          typedef vector_interface<T>* ivector_ptr;
 
          static inline T process(const ivector_ptr v)
          {
             const T* vec = v->vec()->vds().data();
             const std::size_t vec_size = v->vec()->vds().size();
 
             loop_unroll::details lud(vec_size);
 
             if (vec_size <= static_cast<std::size_t>(lud.batch_size))
             {
                T result = T(0);
                int i    = 0;
 
                exprtk_disable_fallthrough_begin
                switch (vec_size)
                {
                   #define case_stmt(N)         \
                   case N : result += vec[i++]; \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(16) case_stmt(15)
                   case_stmt(14) case_stmt(13)
                   case_stmt(12) case_stmt(11)
                   case_stmt(10) case_stmt( 9)
                   case_stmt( 8) case_stmt( 7)
                   case_stmt( 6) case_stmt( 5)
                   #endif
                   case_stmt( 4) case_stmt( 3)
                   case_stmt( 2) case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef case_stmt
 
                return result;
             }
 
             T r[] = {
                       T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0),
                       T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0)
                     };
 
             const T* upper_bound = vec + lud.upper_bound;
 
             while (vec < upper_bound)
             {
                #define exprtk_loop(N) \
                r[N] += vec[N];        \
 
                exprtk_loop( 0) exprtk_loop( 1)
                exprtk_loop( 2) exprtk_loop( 3)
                #ifndef exprtk_disable_superscalar_unroll
                exprtk_loop( 4) exprtk_loop( 5)
                exprtk_loop( 6) exprtk_loop( 7)
                exprtk_loop( 8) exprtk_loop( 9)
                exprtk_loop(10) exprtk_loop(11)
                exprtk_loop(12) exprtk_loop(13)
                exprtk_loop(14) exprtk_loop(15)
                #endif
 
                vec += lud.batch_size;
             }
 
             int i = 0;
 
             exprtk_disable_fallthrough_begin
             switch (lud.remainder)
             {
                #define case_stmt(N)       \
                case N : r[0] += vec[i++]; \
 
                #ifndef exprtk_disable_superscalar_unroll
                case_stmt(15) case_stmt(14)
                case_stmt(13) case_stmt(12)
                case_stmt(11) case_stmt(10)
                case_stmt( 9) case_stmt( 8)
                case_stmt( 7) case_stmt( 6)
                case_stmt( 5) case_stmt( 4)
                #endif
                case_stmt( 3) case_stmt( 2)
                case_stmt( 1)
             }
             exprtk_disable_fallthrough_end
 
             #undef exprtk_loop
             #undef case_stmt
 
             return (r[ 0] + r[ 1] + r[ 2] + r[ 3])
                    #ifndef exprtk_disable_superscalar_unroll
                  + (r[ 4] + r[ 5] + r[ 6] + r[ 7])
                  + (r[ 8] + r[ 9] + r[10] + r[11])
                  + (r[12] + r[13] + r[14] + r[15])
                    #endif
                    ;
          }
       };
 
       template <typename T>
       struct vec_mul_op
       {
          typedef vector_interface<T>* ivector_ptr;
 
          static inline T process(const ivector_ptr v)
          {
             const T* vec = v->vec()->vds().data();
             const std::size_t vec_size = v->vec()->vds().size();
 
             loop_unroll::details lud(vec_size);
 
             if (vec_size <= static_cast<std::size_t>(lud.batch_size))
             {
                T result = T(1);
                int i    = 0;
 
                exprtk_disable_fallthrough_begin
                switch (vec_size)
                {
                   #define case_stmt(N)         \
                   case N : result *= vec[i++]; \
 
                   #ifndef exprtk_disable_superscalar_unroll
                   case_stmt(16) case_stmt(15)
                   case_stmt(14) case_stmt(13)
                   case_stmt(12) case_stmt(11)
                   case_stmt(10) case_stmt( 9)
                   case_stmt( 8) case_stmt( 7)
                   case_stmt( 6) case_stmt( 5)
                   #endif
                   case_stmt( 4) case_stmt( 3)
                   case_stmt( 2) case_stmt( 1)
                }
                exprtk_disable_fallthrough_end
 
                #undef case_stmt
 
                return result;
             }
 
             T r[] = {
                       T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1),
                       T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1)
                     };
 
             const T* upper_bound = vec + lud.upper_bound;
 
             while (vec < upper_bound)
             {
                #define exprtk_loop(N) \
                r[N] *= vec[N];        \
 
                exprtk_loop( 0) exprtk_loop( 1)
                exprtk_loop( 2) exprtk_loop( 3)
                #ifndef exprtk_disable_superscalar_unroll
                exprtk_loop( 4) exprtk_loop( 5)
                exprtk_loop( 6) exprtk_loop( 7)
                exprtk_loop( 8) exprtk_loop( 9)
                exprtk_loop(10) exprtk_loop(11)
                exprtk_loop(12) exprtk_loop(13)
                exprtk_loop(14) exprtk_loop(15)
                #endif
 
                vec += lud.batch_size;
             }
 
             int i = 0;
 
             exprtk_disable_fallthrough_begin
             switch (lud.remainder)
             {
                #define case_stmt(N)       \
                case N : r[0] *= vec[i++]; \
 
                #ifndef exprtk_disable_superscalar_unroll
                case_stmt(15) case_stmt(14)
                case_stmt(13) case_stmt(12)
                case_stmt(11) case_stmt(10)
                case_stmt( 9) case_stmt( 8)
                case_stmt( 7) case_stmt( 6)
                case_stmt( 5) case_stmt( 4)
                #endif
                case_stmt( 3) case_stmt( 2)
                case_stmt( 1)
             }
             exprtk_disable_fallthrough_end
 
             #undef exprtk_loop
             #undef case_stmt
 
             return (r[ 0] * r[ 1] * r[ 2] * r[ 3])
                    #ifndef exprtk_disable_superscalar_unroll
                  + (r[ 4] * r[ 5] * r[ 6] * r[ 7])
                  + (r[ 8] * r[ 9] * r[10] * r[11])
                  + (r[12] * r[13] * r[14] * r[15])
                    #endif
                    ;
          }
       };
 
       template <typename T>
       struct vec_avg_op
       {
          typedef vector_interface<T>* ivector_ptr;
 
          static inline T process(const ivector_ptr v)
          {
             const std::size_t vec_size = v->vec()->vds().size();
 
             return vec_add_op<T>::process(v) / vec_size;
          }
       };
 
       template <typename T>
       struct vec_min_op
       {
          typedef vector_interface<T>* ivector_ptr;
 
          static inline T process(const ivector_ptr v)
          {
             const T* vec = v->vec()->vds().data();
             const std::size_t vec_size = v->vec()->vds().size();
 
             T result = vec[0];
 
             for (std::size_t i = 1; i < vec_size; ++i)
             {
                const T v_i = vec[i];
 
                if (v_i < result)
                   result = v_i;
             }
 
             return result;
          }
       };
 
       template <typename T>
       struct vec_max_op
       {
          typedef vector_interface<T>* ivector_ptr;
 
          static inline T process(const ivector_ptr v)
          {
             const T* vec = v->vec()->vds().data();
             const std::size_t vec_size = v->vec()->vds().size();
 
             T result = vec[0];
 
             for (std::size_t i = 1; i < vec_size; ++i)
             {
                const T v_i = vec[i];
 
                if (v_i > result)
                   result = v_i;
             }
 
             return result;
          }
       };
 
       template <typename T>
       class vov_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~vov_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T& v0() const = 0;
 
          virtual const T& v1() const = 0;
       };
 
       template <typename T>
       class cov_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~cov_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T c() const = 0;
 
          virtual const T& v() const = 0;
       };
 
       template <typename T>
       class voc_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~voc_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T c() const = 0;
 
          virtual const T& v() const = 0;
       };
 
       template <typename T>
       class vob_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~vob_base_node() {}
4068375e
 
          virtual const T& v() const = 0;
       };
 
       template <typename T>
       class bov_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~bov_base_node() {}
4068375e
 
          virtual const T& v() const = 0;
       };
 
       template <typename T>
       class cob_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~cob_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T c() const = 0;
 
          virtual void set_c(const T) = 0;
 
          virtual expression_node<T>* move_branch(const std::size_t& index) = 0;
       };
 
       template <typename T>
       class boc_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~boc_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T c() const = 0;
 
          virtual void set_c(const T) = 0;
 
          virtual expression_node<T>* move_branch(const std::size_t& index) = 0;
       };
 
       template <typename T>
       class uv_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~uv_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
 
          virtual const T& v() const = 0;
       };
 
       template <typename T>
       class sos_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~sos_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
       };
 
       template <typename T>
       class sosos_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~sosos_base_node() {}
4068375e
 
          inline virtual operator_type operation() const
          {
             return details::e_default;
          }
       };
 
       template <typename T>
       class T0oT1oT2_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~T0oT1oT2_base_node() {}
4068375e
 
          virtual std::string type_id() const = 0;
       };
 
       template <typename T>
       class T0oT1oT2oT3_base_node : public expression_node<T>
       {
       public:
 
a65c8e8b
          virtual ~T0oT1oT2oT3_base_node() {}
4068375e
 
          virtual std::string type_id() const = 0;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class unary_variable_node exprtk_final : public uv_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
 
          explicit unary_variable_node(const T& var)
          : v_(var)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(v_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T& v() const exprtk_override
4068375e
          {
             return v_;
          }
 
       private:
 
a65c8e8b
          unary_variable_node(const unary_variable_node<T,Operation>&) exprtk_delete;
          unary_variable_node<T,Operation>& operator=(const unary_variable_node<T,Operation>&) exprtk_delete;
4068375e
 
          const T& v_;
       };
 
       template <typename T>
a65c8e8b
       class uvouv_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          // UOpr1(v0) Op UOpr2(v1)
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
          typedef typename functor_t::ufunc_t    ufunc_t;
          typedef expression_node<T>*            expression_ptr;
4068375e
 
          explicit uvouv_node(const T& var0,const T& var1,
                              ufunc_t uf0, ufunc_t uf1, bfunc_t bf)
a65c8e8b
          : v0_(var0)
          , v1_(var1)
          , u0_(uf0 )
          , u1_(uf1 )
          , f_ (bf  )
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return f_(u0_(v0_),u1_(v1_));
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_uvouv;
          }
 
          inline const T& v0()
          {
             return v0_;
          }
 
          inline const T& v1()
          {
             return v1_;
          }
 
          inline ufunc_t u0()
          {
             return u0_;
          }
 
          inline ufunc_t u1()
          {
             return u1_;
          }
 
          inline ufunc_t f()
          {
             return f_;
          }
 
       private:
 
a65c8e8b
          uvouv_node(const uvouv_node<T>&) exprtk_delete;
          uvouv_node<T>& operator=(const uvouv_node<T>&) exprtk_delete;
4068375e
 
          const T& v0_;
          const T& v1_;
          const ufunc_t u0_;
          const ufunc_t u1_;
          const bfunc_t f_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class unary_branch_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
a65c8e8b
          typedef Operation                      operation_t;
          typedef expression_node<T>*            expression_ptr;
4068375e
          typedef std::pair<expression_ptr,bool> branch_t;
 
          explicit unary_branch_node(expression_ptr branch)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(branch_.first->value());
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation()
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
          inline void release()
          {
             branch_.second = false;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          unary_branch_node(const unary_branch_node<T,Operation>&) exprtk_delete;
          unary_branch_node<T,Operation>& operator=(const unary_branch_node<T,Operation>&) exprtk_delete;
4068375e
 
          branch_t branch_;
       };
 
       template <typename T> struct is_const                { enum {result = 0}; };
       template <typename T> struct is_const <const T>      { enum {result = 1}; };
       template <typename T> struct is_const_ref            { enum {result = 0}; };
       template <typename T> struct is_const_ref <const T&> { enum {result = 1}; };
       template <typename T> struct is_ref                  { enum {result = 0}; };
       template <typename T> struct is_ref<T&>              { enum {result = 1}; };
       template <typename T> struct is_ref<const T&>        { enum {result = 0}; };
 
       template <std::size_t State>
       struct param_to_str { static std::string result() { static const std::string r("v"); return r; } };
 
       template <>
       struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } };
 
       #define exprtk_crtype(Type)                          \
       param_to_str<is_const_ref< Type >::result>::result() \
 
       template <typename T>
       struct T0oT1oT2process
       {
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
4068375e
 
          struct mode0
          {
             static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1)
             {
                // (T0 o0 T1) o1 T2
                return bf1(bf0(t0,t1),t2);
             }
 
             template <typename T0, typename T1, typename T2>
             static inline std::string id()
             {
                static const std::string result = "(" + exprtk_crtype(T0) + "o"   +
                                                        exprtk_crtype(T1) + ")o(" +
                                                        exprtk_crtype(T2) + ")"   ;
                return result;
             }
          };
 
          struct mode1
          {
             static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1)
             {
                // T0 o0 (T1 o1 T2)
                return bf0(t0,bf1(t1,t2));
             }
 
             template <typename T0, typename T1, typename T2>
             static inline std::string id()
             {
                static const std::string result = "(" + exprtk_crtype(T0) + ")o(" +
                                                        exprtk_crtype(T1) + "o"   +
                                                        exprtk_crtype(T2) + ")"   ;
                return result;
             }
          };
       };
 
       template <typename T>
       struct T0oT1oT20T3process
       {
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
4068375e
 
          struct mode0
          {
             static inline T process(const T& t0, const T& t1,
                                     const T& t2, const T& t3,
                                     const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2)
             {
                // (T0 o0 T1) o1 (T2 o2 T3)
                return bf1(bf0(t0,t1),bf2(t2,t3));
             }
 
             template <typename T0, typename T1, typename T2, typename T3>
             static inline std::string id()
             {
                static const std::string result = "(" + exprtk_crtype(T0) + "o"  +
                                                        exprtk_crtype(T1) + ")o" +
                                                  "(" + exprtk_crtype(T2) + "o"  +
                                                        exprtk_crtype(T3) + ")"  ;
                return result;
             }
          };
 
          struct mode1
          {
             static inline T process(const T& t0, const T& t1,
                                     const T& t2, const T& t3,
                                     const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2)
             {
                // (T0 o0 (T1 o1 (T2 o2 T3))
                return bf0(t0,bf1(t1,bf2(t2,t3)));
             }
             template <typename T0, typename T1, typename T2, typename T3>
             static inline std::string id()
             {
                static const std::string result = "(" + exprtk_crtype(T0) +  ")o((" +
                                                        exprtk_crtype(T1) +  ")o("  +
                                                        exprtk_crtype(T2) +  "o"    +
                                                        exprtk_crtype(T3) +  "))"   ;
                return result;
             }
          };
 
          struct mode2
          {
             static inline T process(const T& t0, const T& t1,
                                     const T& t2, const T& t3,
                                     const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2)
             {
                // (T0 o0 ((T1 o1 T2) o2 T3)
                return bf0(t0,bf2(bf1(t1,t2),t3));
             }
 
             template <typename T0, typename T1, typename T2, typename T3>
             static inline std::string id()
             {
                static const std::string result = "(" + exprtk_crtype(T0) + ")o((" +
                                                        exprtk_crtype(T1) + "o"    +
                                                        exprtk_crtype(T2) + ")o("  +
                                                        exprtk_crtype(T3) + "))"   ;
                return result;
             }
          };
 
          struct mode3
          {
             static inline T process(const T& t0, const T& t1,
                                     const T& t2, const T& t3,
                                     const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2)
             {
                // (((T0 o0 T1) o1 T2) o2 T3)
                return bf2(bf1(bf0(t0,t1),t2),t3);
             }
 
             template <typename T0, typename T1, typename T2, typename T3>
             static inline std::string id()
             {
                static const std::string result = "((" + exprtk_crtype(T0) + "o"    +
                                                         exprtk_crtype(T1) + ")o("  +
                                                         exprtk_crtype(T2) + "))o(" +
                                                         exprtk_crtype(T3) + ")";
                return result;
             }
          };
 
          struct mode4
          {
             static inline T process(const T& t0, const T& t1,
                                     const T& t2, const T& t3,
                                     const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2)
             {
                // ((T0 o0 (T1 o1 T2)) o2 T3
                return bf2(bf0(t0,bf1(t1,t2)),t3);
             }
 
             template <typename T0, typename T1, typename T2, typename T3>
             static inline std::string id()
             {
                static const std::string result = "((" + exprtk_crtype(T0) + ")o("  +
                                                         exprtk_crtype(T1) + "o"    +
                                                         exprtk_crtype(T2) + "))o(" +
                                                         exprtk_crtype(T3) + ")"    ;
                return result;
             }
          };
       };
 
       #undef exprtk_crtype
 
       template <typename T, typename T0, typename T1>
       struct nodetype_T0oT1 { static const typename expression_node<T>::node_type result; };
       template <typename T, typename T0, typename T1>
       const typename expression_node<T>::node_type nodetype_T0oT1<T,T0,T1>::result = expression_node<T>::e_none;
 
a65c8e8b
       #define synthesis_node_type_define(T0_, T1_, v_)                                                          \
4068375e
       template <typename T, typename T0, typename T1>                                                           \
       struct nodetype_T0oT1<T,T0_,T1_> { static const typename expression_node<T>::node_type result; };         \
       template <typename T, typename T0, typename T1>                                                           \
       const typename expression_node<T>::node_type nodetype_T0oT1<T,T0_,T1_>::result = expression_node<T>:: v_; \
 
       synthesis_node_type_define(const T0&, const T1&,  e_vov)
       synthesis_node_type_define(const T0&, const T1 ,  e_voc)
       synthesis_node_type_define(const T0 , const T1&,  e_cov)
       synthesis_node_type_define(      T0&,       T1&, e_none)
       synthesis_node_type_define(const T0 , const T1 , e_none)
       synthesis_node_type_define(      T0&, const T1 , e_none)
       synthesis_node_type_define(const T0 ,       T1&, e_none)
       synthesis_node_type_define(const T0&,       T1&, e_none)
       synthesis_node_type_define(      T0&, const T1&, e_none)
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1, typename T2>
       struct nodetype_T0oT1oT2 { static const typename expression_node<T>::node_type result; };
       template <typename T, typename T0, typename T1, typename T2>
       const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0,T1,T2>::result = expression_node<T>::e_none;
 
a65c8e8b
       #define synthesis_node_type_define(T0_, T1_, T2_, v_)                                                            \
4068375e
       template <typename T, typename T0, typename T1, typename T2>                                                     \
       struct nodetype_T0oT1oT2<T,T0_,T1_,T2_> { static const typename expression_node<T>::node_type result; };         \
       template <typename T, typename T0, typename T1, typename T2>                                                     \
       const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0_,T1_,T2_>::result = expression_node<T>:: v_; \
 
       synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov)
       synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc)
       synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov)
       synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov)
       synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc)
       synthesis_node_type_define(const T0 , const T1 , const T2 , e_none )
       synthesis_node_type_define(const T0 , const T1 , const T2&, e_none )
       synthesis_node_type_define(const T0&, const T1 , const T2 , e_none )
       synthesis_node_type_define(      T0&,       T1&,       T2&, e_none )
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1, typename T2, typename T3>
       struct nodetype_T0oT1oT2oT3 { static const typename expression_node<T>::node_type result; };
       template <typename T, typename T0, typename T1, typename T2, typename T3>
       const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result = expression_node<T>::e_none;
 
a65c8e8b
       #define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_)                                                              \
4068375e
       template <typename T, typename T0, typename T1, typename T2, typename T3>                                               \
       struct nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_> { static const typename expression_node<T>::node_type result; };         \
       template <typename T, typename T0, typename T1, typename T2, typename T3>                                               \
       const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_>::result = expression_node<T>:: v_; \
 
       synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov)
       synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc)
       synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov)
       synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov)
       synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov)
       synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov)
       synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc)
       synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc)
       synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov)
       synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none   )
       synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none   )
       synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none   )
       synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none   )
       synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none   )
       synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none   )
       synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none   )
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1>
a65c8e8b
       class T0oT1 exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
4068375e
          typedef T value_type;
          typedef T0oT1<T,T0,T1> node_type;
 
          T0oT1(T0 p0, T1 p1, const bfunc_t p2)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , f_ (p2)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1<T,T0,T1>::result;
             return result;
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return e_default;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return f_(t0_,t1_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline bfunc_t f() const
          {
             return f_;
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator,
                                                     T0 p0, T1 p1,
                                                     bfunc_t p2)
          {
             return allocator
                      .template allocate_type<node_type, T0, T1, bfunc_t&>
                         (p0, p1, p2);
          }
 
       private:
 
a65c8e8b
          T0oT1(const T0oT1<T,T0,T1>&) exprtk_delete;
          T0oT1<T,T0,T1>& operator=(const T0oT1<T,T0,T1>&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          const bfunc_t f_;
       };
 
       template <typename T, typename T0, typename T1, typename T2, typename ProcessMode>
a65c8e8b
       class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
4068375e
          typedef T value_type;
          typedef T0oT1oT2<T,T0,T1,T2,ProcessMode> node_type;
          typedef ProcessMode process_mode_t;
 
          T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
          , f0_(p3)
          , f1_(p4)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result;
             return result;
          }
 
a65c8e8b
          inline operator_type operation()
4068375e
          {
             return e_default;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return ProcessMode::process(t0_, t1_, t2_, f0_, f1_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline T2 t2() const
          {
             return t2_;
          }
 
          bfunc_t f0() const
          {
             return f0_;
          }
 
          bfunc_t f1() const
          {
             return f1_;
          }
 
a65c8e8b
          std::string type_id() const exprtk_override
4068375e
          {
             return id();
          }
 
          static inline std::string id()
          {
             return process_mode_t::template id<T0,T1,T2>();
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4)
          {
             return allocator
                       .template allocate_type<node_type, T0, T1, T2, bfunc_t, bfunc_t>
                          (p0, p1, p2, p3, p4);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
          const bfunc_t f0_;
          const bfunc_t f1_;
       };
 
       template <typename T, typename T0_, typename T1_, typename T2_, typename T3_, typename ProcessMode>
a65c8e8b
       class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::bfunc_t    bfunc_t;
4068375e
          typedef T value_type;
          typedef T0_ T0;
          typedef T1_ T1;
          typedef T2_ T2;
          typedef T3_ T3;
          typedef T0oT1oT2oT3<T,T0,T1,T2,T3,ProcessMode> node_type;
          typedef ProcessMode process_mode_t;
 
          T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
          , t3_(p3)
          , f0_(p4)
          , f1_(p5)
          , f2_(p6)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline T2 t2() const
          {
             return t2_;
          }
 
          inline T3 t3() const
          {
             return t3_;
          }
 
          inline bfunc_t f0() const
          {
             return f0_;
          }
 
          inline bfunc_t f1() const
          {
             return f1_;
          }
 
          inline bfunc_t f2() const
          {
             return f2_;
          }
 
a65c8e8b
          inline std::string type_id() const exprtk_override
4068375e
          {
             return id();
          }
 
          static inline std::string id()
          {
             return process_mode_t::template id<T0, T1, T2, T3>();
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator,
                                                     T0 p0, T1 p1, T2 p2, T3 p3,
                                                     bfunc_t p4, bfunc_t p5, bfunc_t p6)
          {
             return allocator
                       .template allocate_type<node_type, T0, T1, T2, T3, bfunc_t, bfunc_t>
                          (p0, p1, p2, p3, p4, p5, p6);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2oT3(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
          T3 t3_;
          const bfunc_t f0_;
          const bfunc_t f1_;
          const bfunc_t f2_;
       };
 
       template <typename T, typename T0, typename T1, typename T2>
a65c8e8b
       class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::tfunc_t    tfunc_t;
4068375e
          typedef T value_type;
          typedef T0oT1oT2_sf3<T,T0,T1,T2> node_type;
 
          T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
          , f_ (p3)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result;
             return result;
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return e_default;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return f_(t0_, t1_, t2_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline T2 t2() const
          {
             return t2_;
          }
 
          tfunc_t f() const
          {
             return f_;
          }
 
          std::string type_id() const
          {
             return id();
          }
 
          static inline std::string id()
          {
             return "sf3";
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3)
          {
             return allocator
                      .template allocate_type<node_type, T0, T1, T2, tfunc_t>
                         (p0, p1, p2, p3);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2_sf3(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
          const tfunc_t f_;
       };
 
       template <typename T, typename T0, typename T1, typename T2>
       class sf3ext_type_node : public T0oT1oT2_base_node<T>
       {
       public:
 
a65c8e8b
          virtual ~sf3ext_type_node() {}
4068375e
 
          virtual T0 t0() const = 0;
 
          virtual T1 t1() const = 0;
 
          virtual T2 t2() const = 0;
       };
 
       template <typename T, typename T0, typename T1, typename T2, typename SF3Operation>
a65c8e8b
       class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node<T,T0,T1,T2>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::tfunc_t    tfunc_t;
4068375e
          typedef T value_type;
a65c8e8b
          typedef T0oT1oT2_sf3ext<T, T0, T1, T2, SF3Operation> node_type;
4068375e
 
          T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result;
             return result;
          }
 
a65c8e8b
          inline operator_type operation()
4068375e
          {
             return e_default;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return SF3Operation::process(t0_, t1_, t2_);
          }
 
a65c8e8b
          T0 t0() const exprtk_override
4068375e
          {
             return t0_;
          }
 
a65c8e8b
          T1 t1() const exprtk_override
4068375e
          {
             return t1_;
          }
 
a65c8e8b
          T2 t2() const exprtk_override
4068375e
          {
             return t2_;
          }
 
a65c8e8b
          std::string type_id() const exprtk_override
4068375e
          {
             return id();
          }
 
          static inline std::string id()
          {
             return SF3Operation::id();
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2)
          {
             return allocator
                      .template allocate_type<node_type, T0, T1, T2>
                         (p0, p1, p2);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2_sf3ext(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
       };
 
       template <typename T>
       inline bool is_sf3ext_node(const expression_node<T>* n)
       {
          switch (n->type())
          {
             case expression_node<T>::e_vovov : return true;
             case expression_node<T>::e_vovoc : return true;
             case expression_node<T>::e_vocov : return true;
             case expression_node<T>::e_covov : return true;
             case expression_node<T>::e_covoc : return true;
             default                          : return false;
          }
       }
 
       template <typename T, typename T0, typename T1, typename T2, typename T3>
a65c8e8b
       class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::qfunc_t    qfunc_t;
4068375e
          typedef T value_type;
a65c8e8b
          typedef T0oT1oT2oT3_sf4<T, T0, T1, T2, T3> node_type;
4068375e
 
          T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
          , t3_(p3)
          , f_ (p4)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result;
             return result;
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return e_default;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return f_(t0_, t1_, t2_, t3_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline T2 t2() const
          {
             return t2_;
          }
 
          inline T3 t3() const
          {
             return t3_;
          }
 
          qfunc_t f() const
          {
             return f_;
          }
 
          std::string type_id() const
          {
             return id();
          }
 
          static inline std::string id()
          {
             return "sf4";
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4)
          {
             return allocator
                      .template allocate_type<node_type, T0, T1, T2, T3, qfunc_t>
                         (p0, p1, p2, p3, p4);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2oT3_sf4(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
          T3 t3_;
          const qfunc_t f_;
       };
 
       template <typename T, typename T0, typename T1, typename T2, typename T3, typename SF4Operation>
a65c8e8b
       class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node<T>
4068375e
       {
       public:
 
          typedef typename details::functor_t<T> functor_t;
a65c8e8b
          typedef typename functor_t::tfunc_t    tfunc_t;
4068375e
          typedef T value_type;
a65c8e8b
          typedef T0oT1oT2oT3_sf4ext<T, T0, T1, T2, T3, SF4Operation> node_type;
4068375e
 
          T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3)
a65c8e8b
          : t0_(p0)
          , t1_(p1)
          , t2_(p2)
          , t3_(p3)
4068375e
          {}
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result;
             return result;
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return SF4Operation::process(t0_, t1_, t2_, t3_);
          }
 
          inline T0 t0() const
          {
             return t0_;
          }
 
          inline T1 t1() const
          {
             return t1_;
          }
 
          inline T2 t2() const
          {
             return t2_;
          }
 
          inline T3 t3() const
          {
             return t3_;
          }
 
a65c8e8b
          std::string type_id() const exprtk_override
4068375e
          {
             return id();
          }
 
          static inline std::string id()
          {
             return SF4Operation::id();
          }
 
          template <typename Allocator>
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3)
          {
             return allocator
                      .template allocate_type<node_type, T0, T1, T2, T3>
                         (p0, p1, p2, p3);
          }
 
       private:
 
a65c8e8b
          T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) { return (*this); }
4068375e
 
          T0 t0_;
          T1 t1_;
          T2 t2_;
          T3 t3_;
       };
 
       template <typename T>
       inline bool is_sf4ext_node(const expression_node<T>* n)
       {
          switch (n->type())
          {
             case expression_node<T>::e_vovovov : return true;
             case expression_node<T>::e_vovovoc : return true;
             case expression_node<T>::e_vovocov : return true;
             case expression_node<T>::e_vocovov : return true;
             case expression_node<T>::e_covovov : return true;
             case expression_node<T>::e_covocov : return true;
             case expression_node<T>::e_vocovoc : return true;
             case expression_node<T>::e_covovoc : return true;
             case expression_node<T>::e_vococov : return true;
             default                            : return false;
          }
       }
 
       template <typename T, typename T0, typename T1>
       struct T0oT1_define
       {
          typedef details::T0oT1<T, T0, T1> type0;
       };
 
       template <typename T, typename T0, typename T1, typename T2>
       struct T0oT1oT2_define
       {
          typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode0> type0;
          typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode1> type1;
          typedef details::T0oT1oT2_sf3<T, T0, T1, T2> sf3_type;
          typedef details::sf3ext_type_node<T, T0, T1, T2> sf3_type_node;
       };
 
       template <typename T, typename T0, typename T1, typename T2, typename T3>
       struct T0oT1oT2oT3_define
       {
          typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode0> type0;
          typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode1> type1;
          typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode2> type2;
          typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode3> type3;
          typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode4> type4;
          typedef details::T0oT1oT2oT3_sf4<T, T0, T1, T2, T3> sf4_type;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class vov_node exprtk_final : public vov_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
 
          // variable op variable node
          explicit vov_node(const T& var0, const T& var1)
a65c8e8b
          : v0_(var0)
          , v1_(var1)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(v0_,v1_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T& v0() const exprtk_override
4068375e
          {
             return v0_;
          }
 
a65c8e8b
          inline const T& v1() const exprtk_override
4068375e
          {
             return v1_;
          }
 
       protected:
 
          const T& v0_;
          const T& v1_;
 
       private:
 
a65c8e8b
          vov_node(const vov_node<T,Operation>&) exprtk_delete;
          vov_node<T,Operation>& operator=(const vov_node<T,Operation>&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class cov_node exprtk_final : public cov_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
 
          // constant op variable node
          explicit cov_node(const T& const_var, const T& var)
a65c8e8b
          : c_(const_var)
          , v_(var)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(c_,v_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T c() const exprtk_override
4068375e
          {
             return c_;
          }
 
a65c8e8b
          inline const T& v() const exprtk_override
4068375e
          {
             return v_;
          }
 
       protected:
 
          const T  c_;
          const T& v_;
 
       private:
 
a65c8e8b
          cov_node(const cov_node<T,Operation>&) exprtk_delete;
          cov_node<T,Operation>& operator=(const cov_node<T,Operation>&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class voc_node exprtk_final : public voc_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
 
          // variable op constant node
          explicit voc_node(const T& var, const T& const_var)
a65c8e8b
          : v_(var)
          , c_(const_var)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(v_,c_);
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T c() const exprtk_override
4068375e
          {
             return c_;
          }
 
a65c8e8b
          inline const T& v() const exprtk_override
4068375e
          {
             return v_;
          }
 
       protected:
 
          const T& v_;
          const T  c_;
 
       private:
 
a65c8e8b
          voc_node(const voc_node<T,Operation>&) exprtk_delete;
          voc_node<T,Operation>& operator=(const voc_node<T,Operation>&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class vob_node exprtk_final : public vob_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef Operation operation_t;
 
          // variable op constant node
          explicit vob_node(const T& var, const expression_ptr branch)
          : v_(var)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
4068375e
             return Operation::process(v_,branch_.first->value());
          }
 
a65c8e8b
          inline const T& v() const exprtk_override
4068375e
          {
             return v_;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          vob_node(const vob_node<T,Operation>&) exprtk_delete;
          vob_node<T,Operation>& operator=(const vob_node<T,Operation>&) exprtk_delete;
4068375e
 
          const T& v_;
          branch_t branch_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class bov_node exprtk_final : public bov_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef Operation operation_t;
 
          // variable op constant node
          explicit bov_node(const expression_ptr branch, const T& var)
          : v_(var)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
4068375e
             return Operation::process(branch_.first->value(),v_);
          }
 
a65c8e8b
          inline const T& v() const exprtk_override
4068375e
          {
             return v_;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          bov_node(const bov_node<T,Operation>&) exprtk_delete;
          bov_node<T,Operation>& operator=(const bov_node<T,Operation>&) exprtk_delete;
4068375e
 
          const T& v_;
          branch_t branch_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class cob_node exprtk_final : public cob_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef Operation operation_t;
 
          // variable op constant node
          explicit cob_node(const T const_var, const expression_ptr branch)
          : c_(const_var)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
4068375e
             return Operation::process(c_,branch_.first->value());
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T c() const exprtk_override
4068375e
          {
             return c_;
          }
 
a65c8e8b
          inline void set_c(const T new_c) exprtk_override
4068375e
          {
             (*const_cast<T*>(&c_)) = new_c;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
a65c8e8b
          inline expression_node<T>* move_branch(const std::size_t&) exprtk_override
4068375e
          {
             branch_.second = false;
             return branch_.first;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          cob_node(const cob_node<T,Operation>&) exprtk_delete;
          cob_node<T,Operation>& operator=(const cob_node<T,Operation>&) exprtk_delete;
4068375e
 
          const T  c_;
          branch_t branch_;
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class boc_node exprtk_final : public boc_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr,bool> branch_t;
          typedef Operation operation_t;
 
          // variable op constant node
          explicit boc_node(const expression_ptr branch, const T const_var)
          : c_(const_var)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
4068375e
             return Operation::process(branch_.first->value(),c_);
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
a65c8e8b
          inline const T c() const exprtk_override
4068375e
          {
             return c_;
          }
 
a65c8e8b
          inline void set_c(const T new_c) exprtk_override
4068375e
          {
             (*const_cast<T*>(&c_)) = new_c;
          }
 
a65c8e8b
          inline expression_node<T>* branch(const std::size_t&) const exprtk_override
4068375e
          {
             return branch_.first;
          }
 
a65c8e8b
          inline expression_node<T>* move_branch(const std::size_t&) exprtk_override
4068375e
          {
             branch_.second = false;
             return branch_.first;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::template collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          boc_node(const boc_node<T,Operation>&) exprtk_delete;
          boc_node<T,Operation>& operator=(const boc_node<T,Operation>&) exprtk_delete;
4068375e
 
          const T  c_;
          branch_t branch_;
       };
 
       #ifndef exprtk_disable_string_capabilities
       template <typename T, typename SType0, typename SType1, typename Operation>
a65c8e8b
       class sos_node exprtk_final : public sos_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
 
          // string op string node
          explicit sos_node(SType0 p0, SType1 p1)
a65c8e8b
          : s0_(p0)
          , s1_(p1)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return Operation::process(s0_,s1_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
          inline std::string& s0()
          {
             return s0_;
          }
 
          inline std::string& s1()
          {
             return s1_;
          }
 
       protected:
 
          SType0 s0_;
          SType1 s1_;
 
       private:
 
a65c8e8b
          sos_node(const sos_node<T,SType0,SType1,Operation>&) exprtk_delete;
          sos_node<T,SType0,SType1,Operation>& operator=(const sos_node<T,SType0,SType1,Operation>&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
a65c8e8b
       class str_xrox_node exprtk_final : public sos_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
a65c8e8b
          typedef str_xrox_node<T,SType0,SType1,RangePack,Operation> node_type;
4068375e
 
          // string-range op string node
          explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0)
a65c8e8b
          : s0_ (p0 )
          , s1_ (p1 )
          , rp0_(rp0)
4068375e
          {}
 
         ~str_xrox_node()
          {
             rp0_.free();
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             std::size_t r0 = 0;
             std::size_t r1 = 0;
 
             if (rp0_(r0, r1, s0_.size()))
                return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_);
             else
                return T(0);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
          inline std::string& s0()
          {
             return s0_;
          }
 
          inline std::string& s1()
          {
             return s1_;
          }
 
       protected:
 
          SType0    s0_;
          SType1    s1_;
          RangePack rp0_;
 
       private:
 
a65c8e8b
          str_xrox_node(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
a65c8e8b
       class str_xoxr_node exprtk_final : public sos_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
a65c8e8b
          typedef str_xoxr_node<T,SType0,SType1,RangePack,Operation> node_type;
4068375e
 
          // string op string range node
          explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1)
a65c8e8b
          : s0_ (p0 )
          , s1_ (p1 )
          , rp1_(rp1)
4068375e
          {}
 
         ~str_xoxr_node()
          {
             rp1_.free();
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             std::size_t r0 = 0;
             std::size_t r1 = 0;
 
             if (rp1_(r0, r1, s1_.size()))
                return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1));
             else
                return T(0);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
          inline std::string& s0()
          {
             return s0_;
          }
 
          inline std::string& s1()
          {
             return s1_;
          }
 
       protected:
 
          SType0    s0_;
          SType1    s1_;
          RangePack rp1_;
 
       private:
 
a65c8e8b
          str_xoxr_node(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
a65c8e8b
       class str_xroxr_node exprtk_final : public sos_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
a65c8e8b
          typedef str_xroxr_node<T,SType0,SType1,RangePack,Operation> node_type;
4068375e
 
          // string-range op string-range node
          explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1)
a65c8e8b
          : s0_ (p0 )
          , s1_ (p1 )
          , rp0_(rp0)
          , rp1_(rp1)
4068375e
          {}
 
         ~str_xroxr_node()
          {
             rp0_.free();
             rp1_.free();
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             std::size_t r0_0 = 0;
             std::size_t r0_1 = 0;
             std::size_t r1_0 = 0;
             std::size_t r1_1 = 0;
 
             if (
                  rp0_(r0_0, r1_0, s0_.size()) &&
                  rp1_(r0_1, r1_1, s1_.size())
                )
             {
                return Operation::process(
                                           s0_.substr(r0_0, (r1_0 - r0_0) + 1),
                                           s1_.substr(r0_1, (r1_1 - r0_1) + 1)
                                         );
             }
             else
                return T(0);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
          inline std::string& s0()
          {
             return s0_;
          }
 
          inline std::string& s1()
          {
             return s1_;
          }
 
       protected:
 
          SType0    s0_;
          SType1    s1_;
          RangePack rp0_;
          RangePack rp1_;
 
       private:
 
a65c8e8b
          str_xroxr_node(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) exprtk_delete;
4068375e
       };
 
       template <typename T, typename Operation>
a65c8e8b
       class str_sogens_node exprtk_final : public binary_node<T>
4068375e
       {
       public:
 
          typedef expression_node <T>* expression_ptr;
a65c8e8b
          typedef string_base_node<T>* str_base_ptr;
          typedef range_pack      <T>  range_t;
          typedef range_t*             range_ptr;
          typedef range_interface <T>  irange_t;
          typedef irange_t*            irange_ptr;
4068375e
 
          str_sogens_node(const operator_type& opr,
                          expression_ptr branch0,
                          expression_ptr branch1)
a65c8e8b
          : binary_node<T>(opr, branch0, branch1)
          , str0_base_ptr_ (0)
          , str1_base_ptr_ (0)
          , str0_range_ptr_(0)
          , str1_range_ptr_(0)
4068375e
          {
             if (is_generally_string_node(binary_node<T>::branch_[0].first))
             {
                str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == str0_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
 
                if (0 == range)
                   return;
 
                str0_range_ptr_ = &(range->range_ref());
             }
 
             if (is_generally_string_node(binary_node<T>::branch_[1].first))
             {
                str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == str1_base_ptr_)
                   return;
 
                irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first);
 
                if (0 == range)
                   return;
 
                str1_range_ptr_ = &(range->range_ref());
             }
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             if (
                  str0_base_ptr_  &&
                  str1_base_ptr_  &&
                  str0_range_ptr_ &&
                  str1_range_ptr_
                )
             {
                binary_node<T>::branch_[0].first->value();
                binary_node<T>::branch_[1].first->value();
 
                std::size_t str0_r0 = 0;
                std::size_t str0_r1 = 0;
 
                std::size_t str1_r0 = 0;
                std::size_t str1_r1 = 0;
 
a65c8e8b
                const range_t& range0 = (*str0_range_ptr_);
                const range_t& range1 = (*str1_range_ptr_);
4068375e
 
                if (
                     range0(str0_r0, str0_r1, str0_base_ptr_->size()) &&
                     range1(str1_r0, str1_r1, str1_base_ptr_->size())
                   )
                {
                   return Operation::process(
                                              str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1),
                                              str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1)
                                            );
                }
             }
 
             return std::numeric_limits<T>::quiet_NaN();
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
       private:
 
a65c8e8b
          str_sogens_node(const str_sogens_node<T,Operation>&) exprtk_delete;
          str_sogens_node<T,Operation>& operator=(const str_sogens_node<T,Operation>&) exprtk_delete;
4068375e
 
          str_base_ptr str0_base_ptr_;
          str_base_ptr str1_base_ptr_;
          range_ptr    str0_range_ptr_;
          range_ptr    str1_range_ptr_;
       };
 
       template <typename T, typename SType0, typename SType1, typename SType2, typename Operation>
a65c8e8b
       class sosos_node exprtk_final : public sosos_base_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef Operation operation_t;
a65c8e8b
          typedef sosos_node<T, SType0, SType1, SType2, Operation> node_type;
4068375e
 
          // variable op variable node
          explicit sosos_node(SType0 p0, SType1 p1, SType2 p2)
a65c8e8b
          : s0_(p0)
          , s1_(p1)
          , s2_(p2)
4068375e
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             return Operation::process(s0_, s1_, s2_);
4068375e
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return Operation::type();
          }
 
a65c8e8b
          inline operator_type operation() const exprtk_override
4068375e
          {
             return Operation::operation();
          }
 
          inline std::string& s0()
          {
             return s0_;
          }
 
          inline std::string& s1()
          {
             return s1_;
          }
 
          inline std::string& s2()
          {
             return s2_;
          }
 
       protected:
 
          SType0 s0_;
          SType1 s1_;
          SType2 s2_;
 
       private:
 
a65c8e8b
          sosos_node(const node_type&) exprtk_delete;
          node_type& operator=(const node_type&) exprtk_delete;
4068375e
       };
       #endif
 
       template <typename T, typename PowOp>
a65c8e8b
       class ipow_node exprtk_final: public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef PowOp operation_t;
 
          explicit ipow_node(const T& v)
          : v_(v)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return PowOp::result(v_);
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_ipow;
          }
 
       private:
 
a65c8e8b
          ipow_node(const ipow_node<T,PowOp>&) exprtk_delete;
          ipow_node<T,PowOp>& operator=(const ipow_node<T,PowOp>&) exprtk_delete;
4068375e
 
          const T& v_;
       };
 
       template <typename T, typename PowOp>
a65c8e8b
       class bipow_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr, bool> branch_t;
          typedef PowOp operation_t;
 
          explicit bipow_node(expression_ptr branch)
          {
             construct_branch_pair(branch_, branch);
          }
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
a65c8e8b
             assert(branch_.first);
4068375e
             return PowOp::result(branch_.first->value());
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_ipow;
          }
 
a65c8e8b
          void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override
4068375e
          {
             expression_node<T>::ndb_t::collect(branch_, node_delete_list);
          }
 
a65c8e8b
          std::size_t node_depth() const exprtk_override
4068375e
          {
             return expression_node<T>::ndb_t::compute_node_depth(branch_);
          }
 
       private:
 
a65c8e8b
          bipow_node(const bipow_node<T,PowOp>&) exprtk_delete;
          bipow_node<T,PowOp>& operator=(const bipow_node<T,PowOp>&) exprtk_delete;
4068375e
 
          branch_t branch_;
       };
 
       template <typename T, typename PowOp>
a65c8e8b
       class ipowinv_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef PowOp operation_t;
 
          explicit ipowinv_node(const T& v)
          : v_(v)
          {}
 
a65c8e8b
          inline T value() const exprtk_override
4068375e
          {
             return (T(1) / PowOp::result(v_));
          }
 
a65c8e8b
          inline typename expression_node<T>::node_type type() const exprtk_override
4068375e
          {
             return expression_node<T>::e_ipowinv;
          }
 
       private:
 
a65c8e8b
          ipowinv_node(const ipowinv_node<T,PowOp>&) exprtk_delete;
          ipowinv_node<T,PowOp>& operator=(const ipowinv_node<T,PowOp>&) exprtk_delete;
4068375e
 
          const T& v_;
       };
 
       template <typename T, typename PowOp>
a65c8e8b
       class bipowninv_node exprtk_final : public expression_node<T>
4068375e
       {
       public:
 
          typedef expression_node<T>* expression_ptr;
          typedef std::pair<expression_ptr, bool> branch_t;
          typedef PowOp operation_t;
 
          explicit bipowninv_node(expression_ptr branch)
          {
             construct_branch_pair(branch_, branch);
          }