From a9128b137da8bfc2debdc6eadfb9853464d1c83a Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 7 Jul 2022 18:30:31 +0800 Subject: [PATCH 001/144] read config. --- server/config.json | 26 ++++++++++++++++++++++++-- server/src/main.cpp | 19 +++++++++++++++++++ server/src/main.h | 8 ++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/server/config.json b/server/config.json index 4c86ca8f..290b1952 100644 --- a/server/config.json +++ b/server/config.json @@ -1,5 +1,5 @@ -{"servers": - [ +{ + "servers": [ { "username": "s01", "name": "node1", @@ -37,5 +37,27 @@ "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 } + ], + "watchdog": [ + { + "name": "cpu high warning", + "rule": "cpu>90", + "callback": "https://yourSMSurl" + }, + { + "name": "memory high warning", + "rule": "(memory_used/memory_total)*100>90", + "callback": "https://yourSMSurl" + }, + { + "name": "ipv4 offline warning", + "rule": "online4=false", + "callback": "https://yourSMSurl" + }, + { + "name": "you can parse an expression combining any known field", + "rule": "(hdd_used/hdd_total)*100>95", + "callback": "https://yourSMSurl" + } ] } diff --git a/server/src/main.cpp b/server/src/main.cpp index 22ebf1dc..504e39c2 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -411,6 +411,25 @@ int CMain::ReadConfig() } } + // watch dog + // support by: https://cpp.la + ID = 0; + const json_value &jStart = (*pJsonData)["watchdog"]; + if(jStart.type == json_array) + { + for(unsigned i = 0; i < jStart.u.array.length; i++) + { + if(ID < 0 || ID >= NET_MAX_CLIENTS) + continue; + + str_copy(Watchdog(ID)->m_aName, jStart[i]["name"].u.string.ptr, sizeof(Watchdog(ID)->m_aName)); + str_copy(Watchdog(ID)->m_aRule, jStart[i]["rule"].u.string.ptr, sizeof(Watchdog(ID)->m_aRule)); + str_copy(Watchdog(ID)->m_aCallback, jStart[i]["callback"].u.string.ptr, sizeof(Watchdog(ID)->m_aCallback)); + + ID++; + } + } + // if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT // support by: https://cpp.la IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ); diff --git a/server/src/main.h b/server/src/main.h index 2993809a..7cb65920 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -82,6 +82,12 @@ class CMain } m_Stats; } m_aClients[NET_MAX_CLIENTS]; + struct CWatchDog{ + char m_aName[128]; + char m_aRule[128]; + char m_aCallback[128]; + } m_aCWatchDogs[NET_MAX_CLIENTS]; + struct CJSONUpdateThreadData { CClient *pClients; @@ -99,6 +105,8 @@ class CMain int ReadConfig(); int Run(); + CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } + CClient *Client(int ClientID) { return &m_aClients[ClientID]; } CClient *ClientNet(int ClientNetID); const CConfig *Config() const { return &m_Config; } From 77973a5309ce428e333a22fe0583a684203cb3b0 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 11 Jul 2022 19:03:29 +0800 Subject: [PATCH 002/144] 0 and 1 --- server/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config.json b/server/config.json index 290b1952..bcdb432b 100644 --- a/server/config.json +++ b/server/config.json @@ -51,7 +51,7 @@ }, { "name": "ipv4 offline warning", - "rule": "online4=false", + "rule": "online4==0", "callback": "https://yourSMSurl" }, { From 962d564c801a349a507712c4b970f03ae0880cb8 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 12 Jul 2022 13:50:57 +0800 Subject: [PATCH 003/144] copy msg --- server/src/main.cpp | 26 ++++++++++++++++++++++++++ server/src/main.h | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/server/src/main.cpp b/server/src/main.cpp index 504e39c2..abc8ddc3 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -191,6 +191,18 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage) if(rStart["custom"].type == json_string) str_copy(pClient->m_Stats.m_aCustom, rStart["custom"].u.string.ptr, sizeof(pClient->m_Stats.m_aCustom)); + //copy message for watchdog to analysis + WatchdogMessage(pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, + pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, + pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086, + pClient->m_Stats.m_tcpCount, pClient->m_Stats.m_udpCount, pClient->m_Stats.m_processCount, + pClient->m_Stats.m_threadCount, pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx, + pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT,pClient->m_Stats.m_MemTotal, + pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed, + pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_IORead, + pClient->m_Stats.m_IOWrite, pClient->m_Stats.m_CPU, pClient->m_Stats.m_Online4, + pClient->m_Stats.m_Online6); + if(m_Config.m_Verbose) { if(rStart["online4"].type) @@ -234,6 +246,20 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage) return 1; } +void CMain::WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, + double time_10010, double time_189, double time_10086, int tcp, int udp, int process, int thread, + int64_t network_rx, int64_t network_tx, int64_t network_in, int64_t network_out, int memory_total, int memory_used, + int swap_total, int swap_used, int hdd_total, int hdd_used, int io_read, int io_write, int cpu, + int online4, int online6) +{ + printf("%f\t%f\t%f\n", load_1, load_5, load_15); + printf("%f\t%f\t%f\n", ping_10010, ping_189, ping_10086); + printf("%f\t%f\t%f\n", time_10010, time_189, time_10086); + printf("%d\t%d\t%d\t%d\t%ld\t%ld\t%ld\t%ld\t\n", tcp, udp, process, thread, network_rx, network_tx, network_in, network_out); + printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n", memory_total, memory_used, swap_total, swap_used, hdd_total, hdd_used, io_read, io_write); + printf("%d\t%d\t%d\t\n", cpu, online4, online6); +} + void CMain::JSONUpdateThread(void *pUser) { CJSONUpdateThreadData *m_pJSONUpdateThreadData = (CJSONUpdateThreadData *)pUser; diff --git a/server/src/main.h b/server/src/main.h index 7cb65920..fef95c11 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -106,6 +106,11 @@ class CMain int Run(); CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } + void WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, + double time_10010, double time_189, double time_10086, int tcp, int udp, int process, int thread, + int64_t network_rx, int64_t network_tx, int64_t network_in, int64_t network_out, + int memory_total, int memory_used,int swap_total, int swap_used, int hdd_total, + int hdd_used, int io_read, int io_write, int cpu,int online4, int online6); CClient *Client(int ClientID) { return &m_aClients[ClientID]; } CClient *ClientNet(int ClientNetID); From e2a59a5465292805593e783ecd96c6b6bdf67632 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 12 Jul 2022 15:59:24 +0800 Subject: [PATCH 004/144] eval --- server/config.json | 2 +- server/src/exprtk.hpp | 40746 ++++++++++++++++++++++++++++++++++++++++ server/src/main.cpp | 70 +- server/src/main.h | 8 +- 4 files changed, 40811 insertions(+), 15 deletions(-) create mode 100644 server/src/exprtk.hpp diff --git a/server/config.json b/server/config.json index bcdb432b..256b1f3b 100644 --- a/server/config.json +++ b/server/config.json @@ -51,7 +51,7 @@ }, { "name": "ipv4 offline warning", - "rule": "online4==0", + "rule": "online4=0", "callback": "https://yourSMSurl" }, { diff --git a/server/src/exprtk.hpp b/server/src/exprtk.hpp new file mode 100644 index 00000000..eebadb57 --- /dev/null +++ b/server/src/exprtk.hpp @@ -0,0 +1,40746 @@ +/* + ****************************************************************** + * C++ Mathematical Expression Toolkit Library * + * * + * Author: Arash Partow (1999-2022) * + * URL: https://www.partow.net/programming/exprtk/index.html * + * * + * Copyright notice: * + * Free use of the C++ Mathematical Expression Toolkit Library is * + * permitted under the guidelines and in accordance with the most * + * current version of the MIT License. * + * https://www.opensource.org/licenses/MIT * + * * + * Example expressions: * + * (00) (y + x / y) * (x - y / x) * + * (01) (x^2 / sin(2 * pi / y)) - x / 2 * + * (02) sqrt(1 - (x^2)) * + * (03) 1 - sin(2 * x) + cos(pi / y) * + * (04) a * exp(2 * t) + c * + * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) * + * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * + * (07) z := x + sin(2 * pi / y) * + * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * + * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) * + * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) * + * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * + * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * + * * + ****************************************************************** +*/ + + +#ifndef INCLUDE_EXPRTK_HPP +#define INCLUDE_EXPRTK_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 + + #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 + + namespace details + { + typedef char char_t; + typedef char_t* char_ptr; + typedef char_t const* char_cptr; + typedef unsigned char uchar_t; + typedef uchar_t* uchar_ptr; + typedef uchar_t const* uchar_cptr; + typedef unsigned long long int _uint64_t; + typedef long long int _int64_t; + + inline bool is_whitespace(const char_t c) + { + return (' ' == c) || ('\n' == c) || + ('\r' == c) || ('\t' == c) || + ('\b' == c) || ('\v' == c) || + ('\f' == c) ; + } + + inline bool is_operator_char(const char_t c) + { + return ('+' == c) || ('-' == c) || + ('*' == c) || ('/' == c) || + ('^' == c) || ('<' == c) || + ('>' == c) || ('=' == c) || + (',' == c) || ('!' == c) || + ('(' == c) || (')' == c) || + ('[' == c) || (']' == c) || + ('{' == c) || ('}' == c) || + ('%' == c) || (':' == c) || + ('?' == c) || ('&' == c) || + ('|' == c) || (';' == c) ; + } + + inline bool is_letter(const char_t c) + { + return (('a' <= c) && (c <= 'z')) || + (('A' <= c) && (c <= 'Z')) ; + } + + inline bool is_digit(const char_t c) + { + return ('0' <= c) && (c <= '9'); + } + + inline bool is_letter_or_digit(const char_t c) + { + return is_letter(c) || is_digit(c); + } + + inline bool is_left_bracket(const char_t c) + { + return ('(' == c) || ('[' == c) || ('{' == c); + } + + inline bool is_right_bracket(const char_t c) + { + return (')' == c) || (']' == c) || ('}' == c); + } + + inline bool is_bracket(const char_t c) + { + return is_left_bracket(c) || is_right_bracket(c); + } + + inline bool is_sign(const char_t c) + { + return ('+' == c) || ('-' == c); + } + + inline bool is_invalid(const char_t c) + { + return !is_whitespace (c) && + !is_operator_char(c) && + !is_letter (c) && + !is_digit (c) && + ('.' != c) && + ('_' != c) && + ('$' != c) && + ('~' != c) && + ('\'' != c); + } + + inline bool is_valid_string_char(const char_t c) + { + return std::isprint(static_cast(c)) || + 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::tolower(s[i])); + } + } + + inline bool imatch(const char_t c1, const char_t c2) + { + return std::tolower(c1) == std::tolower(c2); + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + if (s1.size() == s2.size()) + { + for (std::size_t i = 0; i < s1.size(); ++i) + { + if (std::tolower(s1[i]) != std::tolower(s2[i])) + { + return false; + } + } + + return true; + } + + return false; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + const std::size_t length = std::min(s1.size(),s2.size()); + + for (std::size_t i = 0; i < length; ++i) + { + const char_t c1 = static_cast(std::tolower(s1[i])); + const char_t c2 = static_cast(std::tolower(s2[i])); + + if (c1 > c2) + return false; + else if (c1 < c2) + return true; + } + + return s1.size() < s2.size(); + } + }; + + #else + inline void case_normalise(std::string&) + {} + + inline bool imatch(const char_t c1, const char_t c2) + { + return c1 == c2; + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + return s1 == s2; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + return s1 < s2; + } + }; + #endif + + inline bool is_valid_sf_symbol(const std::string& symbol) + { + // Special function: $f12 or $F34 + return (4 == symbol.size()) && + ('$' == symbol[0]) && + imatch('f',symbol[1]) && + is_digit(symbol[2]) && + is_digit(symbol[3]); + } + + inline const char_t& front(const std::string& s) + { + return s[0]; + } + + inline const char_t& back(const std::string& s) + { + return s[s.size() - 1]; + } + + inline std::string to_str(int i) + { + if (0 == i) + return std::string("0"); + + std::string result; + + const int sign = (i < 0) ? -1 : 1; + + for ( ; i; i /= 10) + { + result += '0' + static_cast(sign * (i % 10)); + } + + if (sign < 0) + { + result += '-'; + } + + std::reverse(result.begin(), result.end()); + + + return result; + } + + inline std::string to_str(std::size_t i) + { + return to_str(static_cast(i)); + } + + inline bool is_hex_digit(const uchar_t digit) + { + return (('0' <= digit) && (digit <= '9')) || + (('A' <= digit) && (digit <= 'F')) || + (('a' <= digit) && (digit <= 'f')) ; + } + + inline uchar_t hex_to_bin(uchar_t h) + { + if (('0' <= h) && (h <= '9')) + return (h - '0'); + else + return static_cast(std::toupper(h) - 'A'); + } + + template + inline bool parse_hex(Iterator& itr, Iterator end, + char_t& result) + { + 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(*(itr + 2))) << 4 | + hex_to_bin(static_cast(*(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 ::value_type> + inline bool match_impl(const Iterator pattern_begin, + const Iterator pattern_end , + const Iterator data_begin , + const Iterator data_end , + const ValueType zero_or_more, + const ValueType exactly_one ) + { + typedef typename std::iterator_traits::value_type type; + + const Iterator null_itr(0); + + Iterator p_itr = pattern_begin; + Iterator d_itr = data_begin; + Iterator np_itr = null_itr; + Iterator nd_itr = null_itr; + + for ( ; ; ) + { + if (p_itr != pattern_end) + { + const type c = *(p_itr); + + if ((data_end != d_itr) && (Compare::cmp(c,*(d_itr)) || (exactly_one == c))) + { + ++d_itr; + ++p_itr; + continue; + } + else if (zero_or_more == c) + { + while ((pattern_end != p_itr) && (zero_or_more == *(p_itr))) + { + ++p_itr; + } + + const type d = *(p_itr); + + while ((data_end != d_itr) && !(Compare::cmp(d,*(d_itr)) || (exactly_one == d))) + { + ++d_itr; + } + + // set backtrack iterators + np_itr = p_itr - 1; + nd_itr = d_itr + 1; + + continue; + } + } + else if (data_end == d_itr) + return true; + + if ((data_end == d_itr) || (null_itr == nd_itr)) + return false; + + p_itr = np_itr; + d_itr = nd_itr; + } + + return true; + } + + inline bool wc_match(const std::string& wild_card, + const std::string& str) + { + return match_impl( + wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', '?'); + } + + inline bool wc_imatch(const std::string& wild_card, + const std::string& str) + { + return match_impl( + wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', '?'); + } + + inline bool sequence_match(const std::string& pattern, + const std::string& str, + std::size_t& diff_index, + char_t& diff_value) + { + if (str.empty()) + { + return ("Z" == pattern); + } + else if ('*' == pattern[0]) + return false; + + typedef std::string::const_iterator itr_t; + + itr_t p_itr = pattern.begin(); + itr_t s_itr = str .begin(); + + const itr_t p_end = pattern.end(); + const itr_t s_end = str .end(); + + while ((s_end != s_itr) && (p_end != p_itr)) + { + if ('*' == (*p_itr)) + { + const char_t target = static_cast(std::toupper(*(p_itr - 1))); + + if ('*' == target) + { + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; + } + else + ++p_itr; + + while (s_itr != s_end) + { + if (target != std::toupper(*s_itr)) + break; + else + ++s_itr; + } + + continue; + } + else if ( + ('?' != *p_itr) && + std::toupper(*p_itr) != std::toupper(*s_itr) + ) + { + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; + } + + ++p_itr; + ++s_itr; + } + + return ( + (s_end == s_itr) && + ( + (p_end == p_itr) || + ('*' == *p_itr) + ) + ); + } + + static const double pow10[] = { + 1.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, + 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, + 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, + 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 + }; + + static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + + namespace numeric + { + namespace constant + { + static const double e = 2.71828182845904523536028747135266249775724709369996; + static const double pi = 3.14159265358979323846264338327950288419716939937510; + static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; + static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; + static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; + static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; + static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; + static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; + static const double log2 = 0.69314718055994530941723212145817656807550013436026; + static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; + } + + namespace details + { + struct unknown_type_tag { unknown_type_tag() {} }; + struct real_type_tag { real_type_tag () {} }; + struct complex_type_tag { complex_type_tag() {} }; + struct int_type_tag { int_type_tag () {} }; + + template + struct number_type + { + typedef unknown_type_tag type; + number_type() {} + }; + + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ + + #define exprtk_register_complex_type_tag(T) \ + template <> struct number_type > \ + { typedef complex_type_tag type; number_type() {} }; \ + + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { 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 + struct epsilon_type {}; + + #define exprtk_define_epsilon_type(Type, Epsilon) \ + template <> struct epsilon_type \ + { \ + static inline Type value() \ + { \ + const Type epsilon = static_cast(Epsilon); \ + return epsilon; \ + } \ + }; \ + + 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 + + template + inline bool is_nan_impl(const T v, real_type_tag) + { + return std::not_equal_to()(v,v); + } + + template + inline int to_int32_impl(const T v, real_type_tag) + { + return static_cast(v); + } + + template + inline _int64_t to_int64_impl(const T v, real_type_tag) + { + return static_cast<_int64_t>(v); + } + + template + inline bool is_true_impl(const T v) + { + return std::not_equal_to()(T(0),v); + } + + template + inline bool is_false_impl(const T v) + { + return std::equal_to()(T(0),v); + } + + template + inline T abs_impl(const T v, real_type_tag) + { + return ((v < T(0)) ? -v : v); + } + + template + inline T min_impl(const T v0, const T v1, real_type_tag) + { + return std::min(v0,v1); + } + + template + inline T max_impl(const T v0, const T v1, real_type_tag) + { + return std::max(v0,v1); + } + + template + inline T equal_impl(const T v0, const T v1, real_type_tag) + { + const T epsilon = epsilon_type::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::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 + inline T equal_impl(const T v0, const T v1, int_type_tag) + { + return (v0 == v1) ? 1 : 0; + } + + template + inline T expm1_impl(const T v, real_type_tag) + { + // return std::expm1(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 + inline T expm1_impl(const T v, int_type_tag) + { + return T(std::exp(v)) - T(1); + } + + template + inline T nequal_impl(const T v0, const T v1, real_type_tag) + { + typedef real_type_tag rtg; + const T epsilon = epsilon_type::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::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 + inline T nequal_impl(const T v0, const T v1, int_type_tag) + { + return (v0 != v1) ? 1 : 0; + } + + template + inline T modulus_impl(const T v0, const T v1, real_type_tag) + { + return std::fmod(v0,v1); + } + + template + inline T modulus_impl(const T v0, const T v1, int_type_tag) + { + return v0 % v1; + } + + template + inline T pow_impl(const T v0, const T v1, real_type_tag) + { + return std::pow(v0,v1); + } + + template + inline T pow_impl(const T v0, const T v1, int_type_tag) + { + return std::pow(static_cast(v0),static_cast(v1)); + } + + template + inline T logn_impl(const T v0, const T v1, real_type_tag) + { + return std::log(v0) / std::log(v1); + } + + template + inline T logn_impl(const T v0, const T v1, int_type_tag) + { + return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); + } + + template + 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::quiet_NaN(); + } + + template + 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::quiet_NaN(); + } + + template + inline T root_impl(const T v0, const T v1, real_type_tag) + { + if (v1 < T(0)) + return std::numeric_limits::quiet_NaN(); + + const std::size_t n = static_cast(v1); + + if ((v0 < T(0)) && (0 == (n % 2))) + return std::numeric_limits::quiet_NaN(); + + return std::pow(v0, T(1) / n); + } + + template + inline T root_impl(const T v0, const T v1, int_type_tag) + { + return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); + } + + template + 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 + inline T roundn_impl(const T v0, const T v1, real_type_tag) + { + const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1)))); + const T p10 = T(pow10[index]); + + if (v0 < T(0)) + return T(std::ceil ((v0 * p10) - T(0.5)) / p10); + else + return T(std::floor((v0 * p10) + T(0.5)) / p10); + } + + template + inline T roundn_impl(const T v0, const T, int_type_tag) + { + return v0; + } + + template + inline T hypot_impl(const T v0, const T v1, real_type_tag) + { + return std::sqrt((v0 * v0) + (v1 * v1)); + } + + template + inline T hypot_impl(const T v0, const T v1, int_type_tag) + { + return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); + } + + template + inline T atan2_impl(const T v0, const T v1, real_type_tag) + { + return std::atan2(v0,v1); + } + + template + inline T atan2_impl(const T, const T, int_type_tag) + { + return 0; + } + + template + inline T shr_impl(const T v0, const T v1, real_type_tag) + { + return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); + } + + template + inline T shr_impl(const T v0, const T v1, int_type_tag) + { + return v0 >> v1; + } + + template + inline T shl_impl(const T v0, const T v1, real_type_tag) + { + return v0 * std::pow(T(2),static_cast(static_cast(v1))); + } + + template + inline T shl_impl(const T v0, const T v1, int_type_tag) + { + return v0 << v1; + } + + template + inline T sgn_impl(const T v, real_type_tag) + { + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); + } + + template + inline T sgn_impl(const T v, int_type_tag) + { + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); + } + + template + 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 + inline T and_impl(const T v0, const T v1, int_type_tag) + { + return v0 && v1; + } + + template + 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 + inline T nand_impl(const T v0, const T v1, int_type_tag) + { + return !(v0 && v1); + } + + template + 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 + inline T or_impl(const T v0, const T v1, int_type_tag) + { + return (v0 || v1); + } + + template + 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 + inline T nor_impl(const T v0, const T v1, int_type_tag) + { + return !(v0 || v1); + } + + template + 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 + inline T xor_impl(const T v0, const T v1, int_type_tag) + { + return v0 ^ v1; + } + + template + 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 + inline T xnor_impl(const T v0, const T v1, int_type_tag) + { + const bool v0_true = is_true_impl(v0); + const bool v1_true = is_true_impl(v1); + + if ((v0_true && v1_true) || (!v0_true && !v1_true)) + return T(1); + else + return T(0); + } + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erf(TT, impl) \ + inline TT erf_impl(const TT v) { return impl(v); } \ + + exprtk_define_erf( float,::erff) + exprtk_define_erf( double,::erf ) + exprtk_define_erf(long double,::erfl) + #undef exprtk_define_erf + #endif + + template + inline T erf_impl(const T v, real_type_tag) + { + #if defined(_MSC_VER) && (_MSC_VER < 1900) + // Credits: Abramowitz & Stegun Equations 7.1.25-28 + static const T c[] = { + T( 1.26551223), T(1.00002368), + T( 0.37409196), T(0.09678418), + T(-0.18628806), T(0.27886807), + T(-1.13520398), T(1.48851587), + T(-0.82215223), T(0.17087277) + }; + + const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); + + 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])))))))))); + + return (v >= T(0)) ? result : -result; + #else + return erf_impl(v); + #endif + } + + template + inline T erf_impl(const T v, int_type_tag) + { + return erf_impl(static_cast(v),real_type_tag()); + } + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erfc(TT, impl) \ + inline TT erfc_impl(const TT v) { return impl(v); } \ + + exprtk_define_erfc(float ,::erfcf) + exprtk_define_erfc(double ,::erfc ) + exprtk_define_erfc(long double,::erfcl) + #undef exprtk_define_erfc + #endif + + template + inline T erfc_impl(const T v, real_type_tag) + { + #if defined(_MSC_VER) && (_MSC_VER < 1900) + return T(1) - erf_impl(v,real_type_tag()); + #else + return erfc_impl(v); + #endif + } + + template + inline T erfc_impl(const T v, int_type_tag) + { + return erfc_impl(static_cast(v),real_type_tag()); + } + + template + inline T ncdf_impl(const T v, real_type_tag) + { + const T cnd = T(0.5) * (T(1) + + erf_impl(abs_impl(v,real_type_tag()) / + T(numeric::constant::sqrt2),real_type_tag())); + return (v < T(0)) ? (T(1) - cnd) : cnd; + } + + template + inline T ncdf_impl(const T v, int_type_tag) + { + return ncdf_impl(static_cast(v),real_type_tag()); + } + + template + inline T sinc_impl(const T v, real_type_tag) + { + if (std::abs(v) >= std::numeric_limits::epsilon()) + return(std::sin(v) / v); + else + return T(1); + } + + template + inline T sinc_impl(const T v, int_type_tag) + { + return sinc_impl(static_cast(v),real_type_tag()); + } + + template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } + template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } + template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } + template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } + template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } + template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } + template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } + template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } + template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } + template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } + template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } + template inline T log_impl(const T v, real_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } + template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } + template inline T neg_impl(const T v, real_type_tag) { return -v; } + template inline T pos_impl(const T v, real_type_tag) { return +v; } + template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } + template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } + template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } + template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } + template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } + template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } + template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } + template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } + template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } + template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } + template inline T d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); } + template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); } + template inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to()(T(0),v) ? T(0) : T(1)); } + template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } + template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } + + template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } + template inline T const_e_impl(real_type_tag) { return T(numeric::constant::e); } + template inline T const_qnan_impl(real_type_tag) { return std::numeric_limits::quiet_NaN(); } + + template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } + template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } + template inline T log_impl(const T v, int_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } + template inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } + template inline T neg_impl(const T v, int_type_tag) { return -v; } + template inline T pos_impl(const T v, int_type_tag) { return +v; } + template inline T ceil_impl(const T v, int_type_tag) { return v; } + template inline T floor_impl(const T v, int_type_tag) { return v; } + template inline T round_impl(const T v, int_type_tag) { return v; } + template inline T notl_impl(const T v, int_type_tag) { return !v; } + template inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } + template inline T frac_impl(const T , int_type_tag) { return T(0); } + template inline T trunc_impl(const T v, int_type_tag) { return v; } + template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T asin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T atan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cot_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sec_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T csc_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + + template + inline bool is_integer_impl(const T& v, real_type_tag) + { + return std::equal_to()(T(0),std::fmod(v,T(1))); + } + + template + inline bool is_integer_impl(const T&, int_type_tag) + { + return true; + } + } + + template + struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; + + template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9 }; }; + template <> struct numeric_info { enum { min_exp = -38, max_exp = +38 }; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; + + template + inline int to_int32(const T v) + { + const typename details::number_type::type num_type; + return to_int32_impl(v, num_type); + } + + template + inline _int64_t to_int64(const T v) + { + const typename details::number_type::type num_type; + return to_int64_impl(v, num_type); + } + + template + inline bool is_nan(const T v) + { + const typename details::number_type::type num_type; + return is_nan_impl(v, num_type); + } + + template + inline T min(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return min_impl(v0, v1, num_type); + } + + template + inline T max(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return max_impl(v0, v1, num_type); + } + + template + inline T equal(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return equal_impl(v0, v1, num_type); + } + + template + inline T nequal(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nequal_impl(v0, v1, num_type); + } + + template + inline T modulus(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return modulus_impl(v0, v1, num_type); + } + + template + inline T pow(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return pow_impl(v0, v1, num_type); + } + + template + inline T logn(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return logn_impl(v0, v1, num_type); + } + + template + inline T root(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return root_impl(v0, v1, num_type); + } + + template + inline T roundn(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return roundn_impl(v0, v1, num_type); + } + + template + inline T hypot(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return hypot_impl(v0, v1, num_type); + } + + template + inline T atan2(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return atan2_impl(v0, v1, num_type); + } + + template + inline T shr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return shr_impl(v0, v1, num_type); + } + + template + inline T shl(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return shl_impl(v0, v1, num_type); + } + + template + inline T and_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return and_impl(v0, v1, num_type); + } + + template + inline T nand_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nand_impl(v0, v1, num_type); + } + + template + inline T or_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return or_impl(v0, v1, num_type); + } + + template + inline T nor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nor_impl(v0, v1, num_type); + } + + template + inline T xor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return xor_impl(v0, v1, num_type); + } + + template + inline T xnor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return xnor_impl(v0, v1, num_type); + } + + template + inline bool is_integer(const T v) + { + const typename details::number_type::type num_type; + return is_integer_impl(v, num_type); + } + + template + struct fast_exp + { + static inline T result(T v) + { + unsigned int k = N; + T l = T(1); + + while (k) + { + if (1 == (k % 2)) + { + l *= v; + --k; + } + + v *= v; + k /= 2; + } + + return l; + } + }; + + template struct fast_exp { static inline T result(const T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; + template struct fast_exp { static inline T result(const T v) { return v * v * v; } }; + template struct fast_exp { static inline T result(const T v) { return v * v; } }; + template struct fast_exp { static inline T result(const T v) { return v; } }; + template struct fast_exp { static inline T result(const T ) { return T(1); } }; + + #define exprtk_define_unary_function(FunctionName) \ + template \ + inline T FunctionName (const T v) \ + { \ + const typename details::number_type::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 + 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(sizeof(fract10) / sizeof(double)); + + const int e = std::abs(exponent); + + if (exponent >= std::numeric_limits::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::min_exponent10]); + return T(d / fract10[-exponent + std::numeric_limits::min_exponent10]); + } + } + + template + 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('0'); + + while ((end != itr) && (zero == (*itr))) ++itr; + + bool return_result = true; + unsigned int digit = 0; + const std::size_t length = static_cast(std::distance(itr,end)); + + if (length <= 4) + { + exprtk_disable_fallthrough_begin + switch (length) + { + #ifdef exprtk_use_lut + + #define exprtk_process_digit \ + if ((digit = details::digit_table[(int)*itr++]) < 10) \ + result = result * 10 + (digit); \ + else \ + { \ + return_result = false; \ + break; \ + } \ + + #else + + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ + + #endif + + case 4 : exprtk_process_digit + case 3 : exprtk_process_digit + case 2 : exprtk_process_digit + case 1 : if ((digit = (*itr - zero))>= 10) + { + digit = 0; + return_result = false; + } + + #undef exprtk_process_digit + } + exprtk_disable_fallthrough_end + } + else + return_result = false; + + if (length && return_result) + { + result = result * 10 + static_cast(digit); + ++itr; + } + + result = negative ? -result : result; + return return_result; + } + + template + static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) + { + typedef typename std::iterator_traits::value_type type; + + static const std::size_t nan_length = 3; + + if (std::distance(itr,end) != static_cast(nan_length)) + return false; + + if (static_cast('n') == (*itr)) + { + if ( + (static_cast('a') != *(itr + 1)) || + (static_cast('n') != *(itr + 2)) + ) + { + return false; + } + } + else if ( + (static_cast('A') != *(itr + 1)) || + (static_cast('N') != *(itr + 2)) + ) + { + return false; + } + + t = std::numeric_limits::quiet_NaN(); + + return true; + } + + template + static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative) + { + static const char_t inf_uc[] = "INFINITY"; + static const char_t inf_lc[] = "infinity"; + static const std::size_t inf_length = 8; + + const std::size_t length = static_cast(std::distance(itr,end)); + + if ((3 != length) && (inf_length != length)) + return false; + + char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + + while (end != itr) + { + if (*inf_itr == static_cast(*itr)) + { + ++itr; + ++inf_itr; + continue; + } + else + return false; + } + + if (negative) + t = -std::numeric_limits::infinity(); + else + t = std::numeric_limits::infinity(); + + return true; + } + + template + inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) + { + using namespace details::numeric; + return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp); + } + + template + 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('0'); + + #define parse_digit_1(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + if (end == ++itr) break; \ + + #define parse_digit_2(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + ++itr; \ + + if ('.' != (*itr)) + { + const Iterator curr = itr; + + while ((end != itr) && (zero == (*itr))) ++itr; + + 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; + + const int frac_exponent = static_cast(-std::distance(curr, itr)); + + if (!valid_exponent(frac_exponent, numeric::details::real_type_tag())) + return false; + + d += compute_pow10(tmp_d, frac_exponent); + } + + #undef parse_digit_1 + #undef parse_digit_2 + } + + if (end != itr) + { + typename std::iterator_traits::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(exponent, numeric::details::real_type_tag())) + return false; + else if (exponent) + d = compute_pow10(d,exponent); + + t = static_cast((negative) ? -d : d); + return true; + } + + template + inline bool string_to_real(const std::string& s, T& t) + { + const typename numeric::details::number_type::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 + 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() + : loop_set(e_invalid) + , max_loop_iterations(0) + {} + + 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() + : type(e_none) + , value("") + , position(std::numeric_limits::max()) + {} + + void clear() + { + type = e_none; + value = ""; + position = std::numeric_limits::max(); + } + + template + 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::distance(base_begin,begin)); + return (*this); + } + + template + 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::distance(base_begin,begin)); + return (*this); + } + + template + 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::distance(base_begin,begin)); + return (*this); + } + + template + 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::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 + 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::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_list_t; + typedef token_list_t::iterator token_list_itr_t; + typedef details::char_t char_t; + + generator() + : base_itr_(0) + , s_itr_ (0) + , s_end_ (0) + { + clear(); + } + + inline void clear() + { + base_itr_ = 0; + s_itr_ = 0; + s_end_ = 0; + token_list_.clear(); + token_itr_ = token_list_.end(); + store_token_itr_ = token_list_.end(); + } + + inline bool process(const std::string& str) + { + base_itr_ = str.data(); + s_itr_ = str.data(); + s_end_ = str.data() + str.size(); + + eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); + token_list_.clear(); + + while (!is_end(s_itr_)) + { + scan_token(); + + if (!token_list_.empty() && token_list_.back().is_error()) + return false; + } + + return true; + } + + inline bool empty() const + { + return token_list_.empty(); + } + + inline std::size_t size() const + { + return token_list_.size(); + } + + inline void begin() + { + token_itr_ = token_list_.begin(); + store_token_itr_ = token_list_.begin(); + } + + inline void store() + { + store_token_itr_ = token_itr_; + } + + inline void restore() + { + token_itr_ = store_token_itr_; + } + + inline token_t& next_token() + { + if (token_list_.end() != token_itr_) + { + return *token_itr_++; + } + else + return eof_token_; + } + + inline token_t& peek_next_token() + { + if (token_list_.end() != token_itr_) + { + return *token_itr_; + } + else + return eof_token_; + } + + inline token_t& operator[](const std::size_t& index) + { + if (index < token_list_.size()) + return token_list_[index]; + else + return eof_token_; + } + + inline token_t operator[](const std::size_t& index) const + { + if (index < token_list_.size()) + return token_list_[index]; + else + return eof_token_; + } + + inline bool finished() const + { + return (token_list_.end() == token_itr_); + } + + inline void insert_front(token_t::token_type tk_type) + { + if ( + !token_list_.empty() && + (token_list_.end() != token_itr_) + ) + { + token_t t = *token_itr_; + + t.type = tk_type; + token_itr_ = token_list_.insert(token_itr_,t); + } + } + + inline std::string substr(const std::size_t& begin, const std::size_t& end) const + { + const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; + const details::char_cptr end_itr = ((base_itr_ + end ) < s_end_) ? (base_itr_ + end ) : s_end_; + + return std::string(begin_itr,end_itr); + } + + inline std::string remaining() const + { + if (finished()) + return ""; + else if (token_list_.begin() != token_itr_) + return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); + else + return std::string(base_itr_ + token_itr_->position, s_end_); + } + + private: + + inline bool is_end(details::char_cptr itr) const + { + return (s_end_ == itr); + } + + #ifndef exprtk_disable_comments + inline bool is_comment_start(details::char_cptr itr) const + { + 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; + } + #else + inline bool is_comment_start(details::char_cptr) const + { + return false; + } + #endif + + inline void skip_whitespace() + { + while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) + { + ++s_itr_; + } + } + + inline void skip_comments() + { + #ifndef exprtk_disable_comments + // The following comment styles are supported: + // 1. // .... \n + // 2. # .... \n + // 3. /* .... */ + struct test + { + static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) + { + mode = 0; + if ('#' == c0) { mode = 1; incr = 1; } + else if ('/' == c0) + { + if ('/' == c1) { mode = 1; incr = 2; } + else if ('*' == c1) { mode = 2; incr = 2; } + } + return (0 != mode); + } + + static inline bool comment_end(const char_t c0, const char_t c1, int& mode) + { + if ( + ((1 == mode) && ('\n' == c0)) || + ((2 == mode) && ( '*' == c0) && ('/' == c1)) + ) + { + mode = 0; + return true; + } + else + return false; + } + }; + + int mode = 0; + int increment = 0; + + if (is_end(s_itr_)) + return; + else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) + return; + + details::char_cptr cmt_start = s_itr_; + + s_itr_ += increment; + + while (!is_end(s_itr_)) + { + if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) + { + ++s_itr_; + return; + } + + if ((2 == mode)) + { + if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) + { + s_itr_ += 2; + return; + } + } + + ++s_itr_; + } + + if (2 == mode) + { + token_t t; + t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); + token_list_.push_back(t); + } + #endif + } + + inline void scan_token() + { + if (details::is_whitespace(*s_itr_)) + { + skip_whitespace(); + return; + } + else if (is_comment_start(s_itr_)) + { + skip_comments(); + return; + } + else if (details::is_operator_char(*s_itr_)) + { + scan_operator(); + return; + } + else if (details::is_letter(*s_itr_)) + { + scan_symbol(); + return; + } + else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) + { + scan_number(); + return; + } + else if ('$' == (*s_itr_)) + { + scan_special_function(); + return; + } + #ifndef exprtk_disable_string_capabilities + else if ('\'' == (*s_itr_)) + { + scan_string(); + return; + } + #endif + else if ('~' == (*s_itr_)) + { + token_t t; + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + token_list_.push_back(t); + ++s_itr_; + return; + } + else + { + token_t t; + t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + ++s_itr_; + } + } + + inline void scan_operator() + { + token_t t; + + const char_t c0 = s_itr_[0]; + + if (!is_end(s_itr_ + 1)) + { + const char_t c1 = s_itr_[1]; + + if (!is_end(s_itr_ + 2)) + { + const char_t c2 = s_itr_[2]; + + if ((c0 == '<') && (c1 == '=') && (c2 == '>')) + { + t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); + token_list_.push_back(t); + s_itr_ += 3; + return; + } + } + + token_t::token_type ttype = token_t::e_none; + + if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; + else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; + else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; + else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; + else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; + else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; + else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; + else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; + else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; + else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; + else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; + else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; + else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; + + if (token_t::e_none != ttype) + { + t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + s_itr_ += 2; + return; + } + } + + if ('<' == c0) + t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); + else if ('>' == c0) + t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); + else if (';' == c0) + t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); + else if ('&' == c0) + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + else if ('|' == c0) + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + else + t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); + + token_list_.push_back(t); + ++s_itr_; + } + + inline void scan_symbol() + { + details::char_cptr initial_itr = s_itr_; + + while (!is_end(s_itr_)) + { + if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) + { + if ('.' != (*s_itr_)) + break; + /* + Permit symbols that contain a 'dot' + Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 + Disallowed: .abc, abc., abc., abc. + */ + if ( + (s_itr_ != initial_itr) && + !is_end(s_itr_ + 1) && + !details::is_letter_or_digit(*(s_itr_ + 1)) && + ('_' != (*(s_itr_ + 1))) + ) + break; + } + + ++s_itr_; + } + + token_t t; + t.set_symbol(initial_itr,s_itr_,base_itr_); + token_list_.push_back(t); + } + + inline void scan_number() + { + /* + Attempt to match a valid numeric value in one of the following formats: + (01) 123456 + (02) 123456. + (03) 123.456 + (04) 123.456e3 + (05) 123.456E3 + (06) 123.456e+3 + (07) 123.456E+3 + (08) 123.456e-3 + (09) 123.456E-3 + (00) .1234 + (11) .1234e3 + (12) .1234E+3 + (13) .1234e+3 + (14) .1234E-3 + (15) .1234e-3 + */ + + details::char_cptr initial_itr = s_itr_; + bool dot_found = false; + bool e_found = false; + bool post_e_sign_found = false; + bool post_e_digit_found = false; + token_t t; + + while (!is_end(s_itr_)) + { + if ('.' == (*s_itr_)) + { + if (dot_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + dot_found = true; + ++s_itr_; + + continue; + } + else if ('e' == std::tolower(*s_itr_)) + { + const char_t& c = *(s_itr_ + 1); + + if (is_end(s_itr_ + 1)) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else if ( + ('+' != c) && + ('-' != c) && + !details::is_digit(c) + ) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + e_found = true; + ++s_itr_; + + continue; + } + else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) + { + if (post_e_sign_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + post_e_sign_found = true; + ++s_itr_; + + continue; + } + else if (e_found && details::is_digit(*s_itr_)) + { + post_e_digit_found = true; + ++s_itr_; + + continue; + } + else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) + break; + else + ++s_itr_; + } + + t.set_numeric(initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + inline void scan_special_function() + { + details::char_cptr initial_itr = s_itr_; + token_t t; + + // $fdd(x,x,x) = at least 11 chars + if (std::distance(s_itr_,s_end_) < 11) + { + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 11, s_end_), + base_itr_); + token_list_.push_back(t); + + return; + } + + if ( + !(('$' == *s_itr_) && + (details::imatch ('f',*(s_itr_ + 1))) && + (details::is_digit(*(s_itr_ + 2))) && + (details::is_digit(*(s_itr_ + 3)))) + ) + { + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 4, s_end_), + base_itr_); + token_list_.push_back(t); + + return; + } + + s_itr_ += 4; // $fdd = 4chars + + t.set_symbol(initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + #ifndef exprtk_disable_string_capabilities + inline void scan_string() + { + details::char_cptr initial_itr = s_itr_ + 1; + token_t t; + + if (std::distance(s_itr_,s_end_) < 2) + { + t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); + token_list_.push_back(t); + + return; + } + + ++s_itr_; + + bool escaped_found = false; + bool escaped = false; + + while (!is_end(s_itr_)) + { + if (!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::distance(base_itr_,initial_itr))); + } + + token_list_.push_back(t); + ++s_itr_; + + return; + } + #endif + + private: + + token_list_t token_list_; + token_list_itr_t token_itr_; + token_list_itr_t store_token_itr_; + token_t eof_token_; + details::char_cptr base_itr_; + details::char_cptr s_itr_; + details::char_cptr s_end_; + + friend class token_scanner; + friend class token_modifier; + friend class token_inserter; + friend class token_joiner; + }; // class generator + + class helper_interface + { + public: + + virtual void init() { } + virtual void reset() { } + virtual bool result() { return true; } + virtual std::size_t process(generator&) { return 0; } + virtual ~helper_interface() { } + }; + + class token_scanner : public helper_interface + { + public: + + virtual ~token_scanner() {} + + explicit token_scanner(const std::size_t& stride) + : stride_(stride) + { + if (stride > 4) + { + throw std::invalid_argument("token_scanner() - Invalid stride value"); + } + } + + inline std::size_t process(generator& g) exprtk_override + { + if (g.token_list_.size() >= stride_) + { + for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) + { + token t; + + switch (stride_) + { + case 1 : + { + const token& t0 = g.token_list_[i]; + + if (!operator()(t0)) + { + return i; + } + } + break; + + case 2 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + + if (!operator()(t0, t1)) + { + return i; + } + } + break; + + case 3 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + const token& t2 = g.token_list_[i + 2]; + + if (!operator()(t0, t1, t2)) + { + return i; + } + } + break; + + case 4 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + const token& t2 = g.token_list_[i + 2]; + const token& t3 = g.token_list_[i + 3]; + + if (!operator()(t0, t1, t2, t3)) + { + return i; + } + } + break; + } + } + } + + return (g.token_list_.size() - stride_ + 1); + } + + virtual bool operator() (const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&, const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&, const token&, const token&) + { + return false; + } + + private: + + const std::size_t stride_; + }; // class token_scanner + + class token_modifier : public helper_interface + { + public: + + inline std::size_t process(generator& g) exprtk_override + { + std::size_t changes = 0; + + for (std::size_t i = 0; i < g.token_list_.size(); ++i) + { + if (modify(g.token_list_[i])) changes++; + } + + return changes; + } + + virtual bool modify(token& t) = 0; + }; + + class token_inserter : public helper_interface + { + public: + + explicit token_inserter(const std::size_t& stride) + : stride_(stride) + { + if (stride > 5) + { + throw std::invalid_argument("token_inserter() - Invalid stride value"); + } + } + + inline std::size_t process(generator& g) exprtk_override + { + if (g.token_list_.empty()) + return 0; + else if (g.token_list_.size() < stride_) + return 0; + + std::size_t changes = 0; + + typedef std::pair insert_t; + std::vector 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(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) + {} + + inline std::size_t process(generator& g) exprtk_override + { + 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(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; + + if (static_cast(i) >= (g.token_list_.size() - 1)) + break; + } + } + + token_list.push_back(g.token_list_.back()); + + assert(token_list.size() <= g.token_list_.size()); + + 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(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; + + if (static_cast(i) >= (g.token_list_.size() - 2)) + 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)); + + assert(token_list.size() <= g.token_list_.size()); + + 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(i), + static_cast(t.position), + t.to_str(t.type).c_str(), + t.value.c_str()); + } + } + + class commutative_inserter : public lexer::token_inserter + { + public: + + using lexer::token_inserter::insert; + + commutative_inserter() + : lexer::token_inserter(2) + {} + + inline void ignore_symbol(const std::string& symbol) + { + ignore_set_.insert(symbol); + } + + inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) + { + bool match = false; + new_token.type = lexer::token::e_mul; + new_token.value = "*"; + new_token.position = t1.position; + + if (t0.type == lexer::token::e_symbol) + { + if (ignore_set_.end() != ignore_set_.find(t0.value)) + { + return -1; + } + else if (!t0.value.empty() && ('$' == t0.value[0])) + { + return -1; + } + } + + if (t1.type == lexer::token::e_symbol) + { + if (ignore_set_.end() != ignore_set_.find(t1.value)) + { + return -1; + } + } + if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; + + return (match) ? 1 : -1; + } + + private: + + std::set ignore_set_; + }; + + class operator_joiner : public token_joiner + { + public: + + explicit operator_joiner(const std::size_t& stride) + : token_joiner(stride) + {} + + inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) + { + // ': =' --> ':=' + if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_assign; + t.value = ":="; + t.position = t0.position; + + return true; + } + // '+ =' --> '+=' + else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_addass; + t.value = "+="; + t.position = t0.position; + + return true; + } + // '- =' --> '-=' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_subass; + t.value = "-="; + t.position = t0.position; + + return true; + } + // '* =' --> '*=' + else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_mulass; + t.value = "*="; + t.position = t0.position; + + return true; + } + // '/ =' --> '/=' + else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_divass; + t.value = "/="; + t.position = t0.position; + + return true; + } + // '% =' --> '%=' + else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_modass; + t.value = "%="; + t.position = t0.position; + + return true; + } + // '> =' --> '>=' + else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_gte; + t.value = ">="; + t.position = t0.position; + + return true; + } + // '< =' --> '<=' + else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_lte; + t.value = "<="; + t.position = t0.position; + + return true; + } + // '= =' --> '==' + else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_eq; + t.value = "=="; + t.position = t0.position; + + return true; + } + // '! =' --> '!=' + else if ((static_cast(t0.type) == '!') && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_ne; + t.value = "!="; + t.position = t0.position; + + return true; + } + // '< >' --> '<>' + else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) + { + t.type = lexer::token::e_ne; + t.value = "<>"; + t.position = t0.position; + + return true; + } + // '<= >' --> '<=>' + else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) + { + t.type = lexer::token::e_swap; + t.value = "<=>"; + t.position = t0.position; + + return true; + } + // '+ -' --> '-' + else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- +' --> '-' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- -' --> '+' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) + { + /* + Note: May need to reconsider this when wanting to implement + pre/postfix decrement operator + */ + t.type = lexer::token::e_add; + t.value = "+"; + t.position = t0.position; + + return true; + } + else + return false; + } + + inline bool join(const lexer::token& t0, + const lexer::token& t1, + const lexer::token& t2, + lexer::token& t) + { + // '[ * ]' --> '[*]' + if ( + (t0.type == lexer::token::e_lsqrbracket) && + (t1.type == lexer::token::e_mul ) && + (t2.type == lexer::token::e_rsqrbracket) + ) + { + t.type = lexer::token::e_symbol; + t.value = "[*]"; + t.position = t0.position; + + return true; + } + else + return false; + } + }; + + class bracket_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + bracket_checker() + : token_scanner(1) + , state_(true) + {} + + bool result() + { + if (!stack_.empty()) + { + lexer::token t; + t.value = stack_.top().first; + t.position = stack_.top().second; + error_token_ = t; + state_ = false; + + return false; + } + else + return state_; + } + + lexer::token error_token() + { + return error_token_; + } + + void reset() + { + // Why? because msvc doesn't support swap properly. + stack_ = std::stack >(); + state_ = true; + error_token_.clear(); + } + + bool operator() (const lexer::token& t) + { + if ( + !t.value.empty() && + (lexer::token::e_string != t.type) && + (lexer::token::e_symbol != t.type) && + exprtk::details::is_bracket(t.value[0]) + ) + { + details::char_t c = t.value[0]; + + if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); + else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); + else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); + else if (exprtk::details::is_right_bracket(c)) + { + if (stack_.empty()) + { + state_ = false; + error_token_ = t; + + return false; + } + else if (c != stack_.top().first) + { + state_ = false; + error_token_ = t; + + return false; + } + else + stack_.pop(); + } + } + + return true; + } + + private: + + bool state_; + std::stack > stack_; + lexer::token error_token_; + }; + + template + class numeric_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + numeric_checker() + : token_scanner (1) + , current_index_(0) + {} + + bool result() + { + return error_list_.empty(); + } + + void reset() + { + error_list_.clear(); + current_index_ = 0; + } + + bool operator() (const lexer::token& t) + { + if (token::e_number == t.type) + { + T 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::max(); + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + std::size_t current_index_; + std::vector error_list_; + }; + + class symbol_replacer : public lexer::token_modifier + { + private: + + typedef std::map,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 token_pair_t; + typedef std::set 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 error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t) + { + invalid_comb_.insert(std::make_pair(base,t)); + } + + void add_invalid_set1(const lexer::token::token_type t) + { + add_invalid(t, lexer::token::e_assign); + add_invalid(t, lexer::token::e_shr ); + add_invalid(t, lexer::token::e_shl ); + add_invalid(t, lexer::token::e_lte ); + add_invalid(t, lexer::token::e_ne ); + add_invalid(t, lexer::token::e_gte ); + add_invalid(t, lexer::token::e_lt ); + add_invalid(t, lexer::token::e_gt ); + add_invalid(t, lexer::token::e_eq ); + add_invalid(t, lexer::token::e_comma ); + add_invalid(t, lexer::token::e_div ); + add_invalid(t, lexer::token::e_mul ); + add_invalid(t, lexer::token::e_mod ); + add_invalid(t, lexer::token::e_pow ); + add_invalid(t, lexer::token::e_colon ); + } + + bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t) + { + if (details::is_right_bracket(static_cast(base))) + { + switch (t) + { + case lexer::token::e_assign : return (']' != base); + case lexer::token::e_string : return (')' != base); + default : return false; + } + } + else if (details::is_left_bracket(static_cast(base))) + { + if (details::is_right_bracket(static_cast(t))) + return false; + else if (details::is_left_bracket(static_cast(t))) + return false; + else + { + switch (t) + { + case lexer::token::e_number : return false; + case lexer::token::e_symbol : return false; + case lexer::token::e_string : return false; + case lexer::token::e_add : return false; + case lexer::token::e_sub : return false; + case lexer::token::e_colon : return false; + case lexer::token::e_ternary : return false; + default : return true ; + } + } + } + else if (details::is_right_bracket(static_cast(t))) + { + switch (base) + { + case lexer::token::e_number : return false; + case lexer::token::e_symbol : return false; + case lexer::token::e_string : return false; + case lexer::token::e_eof : return false; + case lexer::token::e_colon : return false; + case lexer::token::e_ternary : return false; + default : return true ; + } + } + else if (details::is_left_bracket(static_cast(t))) + { + switch (base) + { + case lexer::token::e_rbracket : return true; + case lexer::token::e_rsqrbracket : return true; + case lexer::token::e_rcrlbracket : return true; + default : return false; + } + } + + return false; + } + + set_t invalid_comb_; + std::vector > error_list_; + }; + + class sequence_validator_3tokens : public lexer::token_scanner + { + private: + + typedef lexer::token::token_type token_t; + typedef std::pair > token_triplet_t; + typedef std::set set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator_3tokens() + : lexer::token_scanner(3) + { + add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); + add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); + add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + + add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + + add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); + } + + bool result() + { + return error_list_.empty(); + } + + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + { + const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); + + if (invalid_comb_.find(p) != invalid_comb_.end()) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::pair error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(const token_t t0, const token_t t1, const token_t t2) + { + invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); + } + + set_t invalid_comb_; + std::vector > 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(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(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(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(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 token_scanner_list; + std::vector token_modifier_list; + std::vector token_joiner_list; + std::vector token_inserter_list; + + lexer::token_scanner* error_token_scanner; + lexer::token_modifier* error_token_modifier; + lexer::token_joiner* error_token_joiner; + lexer::token_inserter* error_token_inserter; + }; + } + + class parser_helper + { + public: + + typedef token token_t; + typedef generator generator_t; + + inline bool init(const std::string& str) + { + if (!lexer_.process(str)) + { + return false; + } + + lexer_.begin(); + + next_token(); + + return true; + } + + inline generator_t& lexer() + { + return lexer_; + } + + inline const generator_t& lexer() const + { + return lexer_; + } + + inline void store_token() + { + lexer_.store(); + store_current_token_ = current_token_; + } + + inline void restore_token() + { + lexer_.restore(); + current_token_ = store_current_token_; + } + + inline void next_token() + { + current_token_ = lexer_.next_token(); + } + + inline const token_t& current_token() const + { + return current_token_; + } + + enum token_advance_mode + { + e_hold = 0, + e_advance = 1 + }; + + inline void advance_token(const token_advance_mode mode) + { + if (e_advance == mode) + { + next_token(); + } + } + + inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) + { + if (current_token().type != ttype) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is(const token_t::token_type& ttype, + const std::string& value, + const token_advance_mode mode = e_advance) + { + if ( + (current_token().type != ttype) || + !exprtk::details::imatch(value,current_token().value) + ) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool peek_token_is(const token_t::token_type& ttype) + { + return (lexer_.peek_next_token().type == ttype); + } + + inline bool peek_token_is(const std::string& s) + { + return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); + } + + private: + + generator_t lexer_; + token_t current_token_; + token_t store_current_token_; + }; + } + + template + class vector_view + { + public: + + typedef T* data_ptr_t; + + vector_view(data_ptr_t data, const std::size_t& size) + : size_(size) + , data_(data) + , data_ref_(0) + {} + + vector_view(const vector_view& vv) + : size_(vv.size_) + , data_(vv.data_) + , data_ref_(0) + {} + + inline void rebase(data_ptr_t data) + { + data_ = data; + + if (!data_ref_.empty()) + { + for (std::size_t i = 0; i < data_ref_.size(); ++i) + { + (*data_ref_[i]) = data; + } + } + } + + inline data_ptr_t data() const + { + return data_; + } + + inline std::size_t size() const + { + return size_; + } + + inline const T& operator[](const std::size_t index) const + { + return data_[index]; + } + + inline T& operator[](const std::size_t index) + { + return data_[index]; + } + + void set_ref(data_ptr_t* data_ref) + { + data_ref_.push_back(data_ref); + } + + private: + + const std::size_t size_; + data_ptr_t data_; + std::vector data_ref_; + }; + + template + inline vector_view make_vector_view(T* data, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(data + offset, size); + } + + template + inline vector_view make_vector_view(std::vector& v, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(v.data() + offset, size); + } + + template class results_context; + + template + struct type_store + { + enum store_type + { + e_unknown, + e_scalar , + e_vector , + e_string + }; + + type_store() + : data(0) + , size(0) + , type(e_unknown) + {} + + union + { + void* data; + T* vec_data; + }; + + std::size_t size; + store_type type; + + class parameter_list + { + public: + + explicit parameter_list(std::vector& pl) + : parameter_list_(pl) + {} + + inline bool empty() const + { + return parameter_list_.empty(); + } + + inline std::size_t size() const + { + return parameter_list_.size(); + } + + inline type_store& operator[](const std::size_t& index) + { + return parameter_list_[index]; + } + + inline const type_store& operator[](const std::size_t& index) const + { + return parameter_list_[index]; + } + + inline type_store& front() + { + return parameter_list_[0]; + } + + inline const type_store& front() const + { + return parameter_list_[0]; + } + + inline type_store& back() + { + return parameter_list_.back(); + } + + inline const type_store& back() const + { + return parameter_list_.back(); + } + + private: + + std::vector& parameter_list_; + + friend class results_context; + }; + + template + struct type_view + { + typedef type_store type_store_t; + typedef ViewType value_t; + + explicit type_view(type_store_t& ts) + : ts_(ts) + , data_(reinterpret_cast(ts_.data)) + {} + + explicit type_view(const type_store_t& ts) + : ts_(const_cast(ts)) + , data_(reinterpret_cast(ts_.data)) + {} + + inline std::size_t size() const + { + return ts_.size; + } + + inline value_t& operator[](const std::size_t& i) + { + return data_[i]; + } + + inline const value_t& operator[](const std::size_t& i) const + { + return data_[i]; + } + + inline const value_t* begin() const { return data_; } + inline value_t* begin() { return data_; } + + inline const value_t* end() const + { + return static_cast(data_ + ts_.size); + } + + inline value_t* end() + { + return static_cast(data_ + ts_.size); + } + + type_store_t& ts_; + value_t* data_; + }; + + typedef type_view vector_view; + typedef type_view string_view; + + struct scalar_view + { + typedef type_store type_store_t; + typedef T value_t; + + explicit scalar_view(type_store_t& ts) + : v_(*reinterpret_cast(ts.data)) + {} + + explicit scalar_view(const type_store_t& ts) + : v_(*reinterpret_cast(const_cast(ts).data)) + {} + + inline value_t& operator() () + { + return v_; + } + + inline const value_t& operator() () const + { + return v_; + } + + template + inline bool to_int(IntType& i) const + { + if (!exprtk::details::numeric::is_integer(v_)) + return false; + + i = static_cast(v_); + + return true; + } + + template + 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(v_); + + return true; + } + + T& v_; + }; + }; + + template + inline std::string to_str(const StringView& view) + { + return std::string(view.begin(),view.size()); + } + + #ifndef exprtk_disable_return_statement + namespace details + { + template class return_node; + template class return_envelope_node; + } + #endif + + template + class results_context + { + public: + + typedef type_store 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 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; + friend class details::return_envelope_node; + #endif + }; + + namespace details + { + enum operator_type + { + e_default , e_null , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_atan2 , e_min , e_max , e_avg , + e_sum , e_prod , e_lt , e_lte , + e_eq , e_equal , e_ne , e_nequal , + e_gte , e_gt , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_mand , e_mor , e_scand , e_scor , + e_shr , e_shl , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_logn , + e_neg , e_pos , e_round , e_roundn , + e_root , e_sqrt , e_sin , e_sinc , + e_sinh , e_sec , e_csc , e_tan , + e_tanh , e_cot , e_clamp , e_iclamp , + e_inrange , e_sgn , e_r2d , e_d2r , + e_d2g , e_g2d , e_hypot , e_notl , + e_erf , e_erfc , e_ncdf , e_frac , + e_trunc , e_assign , e_addass , e_subass , + e_mulass , e_divass , e_modass , e_in , + e_like , e_ilike , e_multi , e_smulti , + e_swap , + + // Do not add new functions/operators after this point. + e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, + e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, + e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, + e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, + e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, + e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, + e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, + e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, + e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, + e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, + e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, + e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, + e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, + e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, + e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, + e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, + e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, + e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, + e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, + e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, + e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, + e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, + e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, + e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, + e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, + e_sffinal = 1100, + e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, + e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, + e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, + e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, + e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, + e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, + e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, + e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, + e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, + e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, + e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, + e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, + e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, + e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, + e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, + e_sf4ext60 = 2060, e_sf4ext61 = 2061 + }; + + inline std::string to_str(const operator_type opr) + { + switch (opr) + { + case e_add : return "+" ; + case e_sub : return "-" ; + case e_mul : return "*" ; + case e_div : return "/" ; + case e_mod : return "%" ; + case e_pow : return "^" ; + case e_assign : return ":=" ; + case e_addass : return "+=" ; + case e_subass : return "-=" ; + case e_mulass : return "*=" ; + case e_divass : return "/=" ; + case e_modass : return "%=" ; + case e_lt : return "<" ; + case e_lte : return "<=" ; + case e_eq : return "==" ; + case e_equal : return "=" ; + case e_ne : return "!=" ; + case e_nequal : return "<>" ; + case e_gte : return ">=" ; + case e_gt : return ">" ; + case e_and : return "and" ; + case e_or : return "or" ; + case e_xor : return "xor" ; + case e_nand : return "nand"; + case e_nor : return "nor" ; + case e_xnor : return "xnor"; + default : return "N/A" ; + } + } + + struct base_operation_t + { + base_operation_t(const operator_type t, const unsigned int& np) + : type(t) + , num_params(np) + {} + + operator_type type; + unsigned int num_params; + }; + + namespace loop_unroll + { + #ifndef exprtk_disable_superscalar_unroll + const unsigned int global_loop_batch_size = 16; + #else + const unsigned int global_loop_batch_size = 4; + #endif + + struct details + { + explicit details(const std::size_t& vsize, + const unsigned int loop_batch_size = global_loop_batch_size) + : batch_size(loop_batch_size ) + , remainder (vsize % batch_size) + , upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0))) + {} + + unsigned int batch_size; + int remainder; + int upper_bound; + }; + } + + #ifdef exprtk_enable_debugging + inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) + { + if (size) + exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + else + exprtk_debug(("%s - addr: %p size: %d\n", + s.c_str(), + ptr, + static_cast(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 + class vec_data_store + { + public: + + typedef vec_data_store type; + typedef T* data_t; + + private: + + struct control_block + { + control_block() + : ref_count(1) + , size (0) + , data (0) + , destruct (true) + {} + + explicit control_block(const std::size_t& dsize) + : ref_count(1 ) + , size (dsize) + , data (0 ) + , destruct (true ) + { create_data(); } + + control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) + : ref_count(1 ) + , size (dsize ) + , data (dptr ) + , destruct (dstrct) + {} + + ~control_block() + { + if (data && destruct && (0 == ref_count)) + { + dump_ptr("~control_block() data",data); + delete[] data; + data = reinterpret_cast(0); + } + } + + static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) + { + if (dsize) + { + if (0 == data_ptr) + return (new control_block(dsize)); + else + return (new control_block(dsize, data_ptr, dstrct)); + } + else + return (new control_block); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + std::size_t size; + data_t data; + bool destruct; + + private: + + control_block(const control_block&) exprtk_delete; + control_block& operator=(const control_block&) exprtk_delete; + + inline void create_data() + { + destruct = true; + data = new T[size]; + std::fill_n(data, size, T(0)); + dump_ptr("control_block::create_data() - data", data, size); + } + }; + + public: + + vec_data_store() + : control_block_(control_block::create(0)) + {} + + explicit vec_data_store(const std::size_t& size) + : control_block_(control_block::create(size,reinterpret_cast(0),true)) + {} + + vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) + : control_block_(control_block::create(size, data, dstrct)) + {} + + vec_data_store(const type& vds) + { + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + + ~vec_data_store() + { + control_block::destroy(control_block_); + } + + type& operator=(const type& vds) + { + if (this != &vds) + { + std::size_t final_size = min_size(control_block_, vds.control_block_); + + vds.control_block_->size = final_size; + control_block_->size = final_size; + + if (control_block_->destruct || (0 == control_block_->data)) + { + control_block::destroy(control_block_); + + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + } + + return (*this); + } + + inline data_t data() + { + return control_block_->data; + } + + inline data_t data() const + { + return control_block_->data; + } + + inline std::size_t size() 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: + + static inline std::size_t min_size(const control_block* cb0, const control_block* cb1) + { + const std::size_t size0 = cb0->size; + const std::size_t size1 = cb1->size; + + if (size0 && size1) + return std::min(size0,size1); + else + return (size0) ? size0 : size1; + } + + control_block* control_block_; + }; + + namespace numeric + { + namespace details + { + template + 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 - Invalid unary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + + template + 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(arg0,arg1); + case e_pow : return pow(arg0,arg1); + case e_atan2 : return atan2(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(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()(arg0,arg1) ? T(1) : T(0); + case e_ne : return std::not_equal_to()(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 (arg0,arg1); + case e_nand : return nand_opr(arg0,arg1); + case e_or : return or_opr (arg0,arg1); + case e_nor : return nor_opr (arg0,arg1); + case e_xor : return xor_opr (arg0,arg1); + case e_xnor : return xnor_opr(arg0,arg1); + case e_root : return root (arg0,arg1); + case e_roundn : return roundn (arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); + case e_hypot : return hypot (arg0,arg1); + case e_shr : return shr (arg0,arg1); + case e_shl : return shl (arg0,arg1); + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + + template + 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(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(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(arg0,arg1); + case e_equal : return arg0 == arg1; + case e_nequal : return arg0 != arg1; + case e_hypot : return hypot(arg0,arg1); + case e_shr : return arg0 >> arg1; + case e_shl : return arg0 << arg1; + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + } + + template + inline T process(const operator_type operation, const T arg) + { + return exprtk::details::numeric::details::process_impl(operation,arg); + } + + template + inline T process(const operator_type operation, const T arg0, const T arg1) + { + return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); + } + } + + template + struct node_collector_interface + { + typedef Node* node_ptr_t; + typedef Node** node_pp_t; + typedef std::vector noderef_list_t; + + virtual ~node_collector_interface() {} + + virtual void collect_nodes(noderef_list_t&) {} + }; + + template + struct node_depth_base; + + template + class expression_node : public node_collector_interface >, + public node_depth_base > + { + public: + + enum node_type + { + e_none , e_null , e_constant , e_unary , + e_binary , e_binary_ext , e_trinary , e_quaternary , + e_vararg , e_conditional , e_while , e_repeat , + e_for , e_switch , e_mswitch , e_return , + e_retenv , e_variable , e_stringvar , e_stringconst , + e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , + e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_vecondition , e_break , + e_continue , e_swap + }; + + typedef T value_type; + typedef expression_node* expression_ptr; + typedef node_collector_interface > nci_t; + typedef typename nci_t::noderef_list_t noderef_list_t; + typedef node_depth_base > ndb_t; + + virtual ~expression_node() {} + + inline virtual T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual expression_node* branch(const std::size_t& index = 0) const + { + return reinterpret_cast(index * 0); + } + + inline virtual node_type type() const + { + return e_none; + } + }; // class expression_node + + template + inline bool is_generally_string_node(const expression_node* node); + + inline bool is_true(const double v) + { + return std::not_equal_to()(0.0,v); + } + + inline bool is_true(const long double v) + { + return std::not_equal_to()(0.0L,v); + } + + inline bool is_true(const float v) + { + return std::not_equal_to()(0.0f,v); + } + + template + inline bool is_true(const std::complex& v) + { + return std::not_equal_to >()(std::complex(0),v); + } + + template + inline bool is_true(const expression_node* node) + { + return std::not_equal_to()(T(0),node->value()); + } + + template + inline bool is_true(const std::pair*,bool>& node) + { + return std::not_equal_to()(T(0),node.first->value()); + } + + template + inline bool is_false(const expression_node* node) + { + return std::equal_to()(T(0),node->value()); + } + + template + inline bool is_false(const std::pair*,bool>& node) + { + return std::equal_to()(T(0),node.first->value()); + } + + template + inline bool is_unary_node(const expression_node* node) + { + return node && (details::expression_node::e_unary == node->type()); + } + + template + inline bool is_neg_unary_node(const expression_node* node) + { + return node && (details::expression_node::e_neg == node->type()); + } + + template + inline bool is_binary_node(const expression_node* node) + { + return node && (details::expression_node::e_binary == node->type()); + } + + template + inline bool is_variable_node(const expression_node* node) + { + return node && (details::expression_node::e_variable == node->type()); + } + + template + inline bool is_ivariable_node(const expression_node* node) + { + return node && + ( + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() + ); + } + + template + inline bool is_vector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_vecelem == node->type()); + } + + template + inline bool is_rebasevector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelem == node->type()); + } + + template + inline bool is_rebasevector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelem == node->type()); + } + + template + inline bool is_vector_node(const expression_node* node) + { + return node && (details::expression_node::e_vector == node->type()); + } + + template + inline bool is_ivector_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case details::expression_node::e_vector : + case details::expression_node::e_vecvalass : + case details::expression_node::e_vecvecass : + case details::expression_node::e_vecopvalass : + case details::expression_node::e_vecopvecass : + case details::expression_node::e_vecvecswap : + case details::expression_node::e_vecvecarith : + case details::expression_node::e_vecvalarith : + case details::expression_node::e_valvecarith : + case details::expression_node::e_vecunaryop : + case details::expression_node::e_vecondition : return true; + default : return false; + } + } + else + return false; + } + + template + inline bool is_constant_node(const expression_node* node) + { + return node && + ( + details::expression_node::e_constant == node->type() || + details::expression_node::e_stringconst == node->type() + ); + } + + template + inline bool is_null_node(const expression_node* node) + { + return node && (details::expression_node::e_null == node->type()); + } + + template + inline bool is_break_node(const expression_node* node) + { + return node && (details::expression_node::e_break == node->type()); + } + + template + inline bool is_continue_node(const expression_node* node) + { + return node && (details::expression_node::e_continue == node->type()); + } + + template + inline bool is_swap_node(const expression_node* node) + { + return node && (details::expression_node::e_swap == node->type()); + } + + template + inline bool is_function(const expression_node* node) + { + return node && (details::expression_node::e_function == node->type()); + } + + template + inline bool is_return_node(const expression_node* node) + { + return node && (details::expression_node::e_return == node->type()); + } + + template class unary_node; + + template + inline bool is_negate_node(const expression_node* node) + { + if (node && is_unary_node(node)) + { + return (details::e_neg == static_cast*>(node)->operation()); + } + else + return false; + } + + template + inline bool branch_deletable(expression_node* node) + { + return (0 != node) && + !is_variable_node(node) && + !is_string_node (node) ; + } + + template + inline bool all_nodes_valid(expression_node* (&b)[N]) + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) return false; + } + + return true; + } + + template class Sequence> + inline bool all_nodes_valid(const Sequence*,Allocator>& b) + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) return false; + } + + return true; + } + + template + inline bool all_nodes_variables(expression_node* (&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 class Sequence> + inline bool all_nodes_variables(Sequence*,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 + class node_collection_destructor + { + public: + + typedef node_collector_interface 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_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(node))); + delete node; + node = reinterpret_cast(0); + } + } + + private: + + static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list) + { + std::deque 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 + inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) + { + for (std::size_t i = 0; i < N; ++i) + { + free_node(node_allocator,b[i]); + } + } + + template class Sequence> + inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) + { + for (std::size_t i = 0; i < b.size(); ++i) + { + free_node(node_allocator,b[i]); + } + + b.clear(); + } + + template + inline void free_node(NodeAllocator&, expression_node*& node) + { + if ((0 == node) || is_variable_node(node) || is_string_node(node)) + { + return; + } + + node_collection_destructor > + ::delete_nodes(node); + } + + template + inline void destroy_node(expression_node*& node) + { + if (0 != node) + { + node_collection_destructor > + ::delete_nodes(node); + } + } + + template + struct node_depth_base + { + typedef Node* node_ptr_t; + typedef std::pair nb_pair_t; + + node_depth_base() + : depth_set(false) + , depth(0) + {} + + 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; + } + + std::size_t compute_node_depth(const nb_pair_t& branch) const + { + if (!depth_set) + { + depth = 1 + (branch.first ? branch.first->node_depth() : 0); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const + { + 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 + 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 + 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 + 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 class Sequence> + std::size_t compute_node_depth(const Sequence& branch_list) const + { + 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 class Sequence> + std::size_t compute_node_depth(const Sequence& branch_list) const + { + 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 + void collect(node_ptr_t const& node, + const bool deletable, + NodeSequence& delete_node_list) const + { + if ((0 != node) && deletable) + { + delete_node_list.push_back(const_cast(&node)); + } + } + + template + void collect(const nb_pair_t& branch, + NodeSequence& delete_node_list) const + { + collect(branch.first, branch.second, delete_node_list); + } + + template + void collect(Node*& node, + NodeSequence& delete_node_list) const + { + collect(node, branch_deletable(node), delete_node_list); + } + + template + void collect(const nb_pair_t(&branch)[N], + 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 class Sequence, + typename NodeSequence> + void collect(const Sequence& branch, + 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 class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + 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 class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + const Sequence& 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 + class vector_holder + { + private: + + typedef Type value_type; + typedef value_type* value_ptr; + typedef const value_ptr const_value_ptr; + + class vector_holder_base + { + public: + + virtual ~vector_holder_base() {} + + inline value_ptr operator[](const std::size_t& index) const + { + return value_at(index); + } + + inline std::size_t size() const + { + return vector_size(); + } + + inline value_ptr data() const + { + return value_at(0); + } + + virtual inline bool rebaseable() const + { + return false; + } + + virtual void set_ref(value_ptr*) {} + + protected: + + virtual value_ptr value_at(const std::size_t&) const = 0; + virtual std::size_t vector_size() const = 0; + }; + + class array_vector_impl : public vector_holder_base + { + public: + + array_vector_impl(const Type* vec, const std::size_t& vec_size) + : vec_(vec) + , size_(vec_size) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const + { + if (index < size_) + return const_cast(vec_ + index); + else + return const_value_ptr(0); + } + + std::size_t vector_size() const + { + return size_; + } + + private: + + array_vector_impl(const array_vector_impl&) exprtk_delete; + array_vector_impl& operator=(const array_vector_impl&) exprtk_delete; + + const Type* vec_; + const std::size_t size_; + }; + + template class Sequence> + class sequence_vector_impl : public vector_holder_base + { + public: + + typedef Sequence sequence_t; + + sequence_vector_impl(sequence_t& seq) + : sequence_(seq) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const + { + return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); + } + + std::size_t vector_size() const + { + return sequence_.size(); + } + + private: + + sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; + sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete; + + sequence_t& sequence_; + }; + + class vector_view_impl : public vector_holder_base + { + public: + + typedef exprtk::vector_view vector_view_t; + + vector_view_impl(vector_view_t& vec_view) + : vec_view_(vec_view) + {} + + void set_ref(value_ptr* ref) + { + vec_view_.set_ref(ref); + } + + virtual inline bool rebaseable() const + { + return true; + } + + protected: + + value_ptr value_at(const std::size_t& index) const + { + return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); + } + + std::size_t vector_size() const + { + return vec_view_.size(); + } + + private: + + vector_view_impl(const vector_view_impl&) exprtk_delete; + vector_view_impl& operator=(const vector_view_impl&) exprtk_delete; + + vector_view_t& vec_view_; + }; + + public: + + typedef typename details::vec_data_store 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 + vector_holder(std::vector& vec) + : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) + {} + + vector_holder(exprtk::vector_view& 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 + class null_node exprtk_final : public expression_node + { + public: + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_null; + } + }; + + template + inline void construct_branch_pair(std::pair*,bool> (&branch)[N], + expression_node* b, + const std::size_t& index) + { + if (b && (index < N)) + { + branch[index] = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void construct_branch_pair(std::pair*,bool>& branch, expression_node* b) + { + if (b) + { + branch = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void init_branches(std::pair*,bool> (&branch)[N], + expression_node* b0, + expression_node* b1 = reinterpret_cast*>(0), + expression_node* b2 = reinterpret_cast*>(0), + expression_node* b3 = reinterpret_cast*>(0), + expression_node* b4 = reinterpret_cast*>(0), + expression_node* b5 = reinterpret_cast*>(0), + expression_node* b6 = reinterpret_cast*>(0), + expression_node* b7 = reinterpret_cast*>(0), + expression_node* b8 = reinterpret_cast*>(0), + expression_node* b9 = reinterpret_cast*>(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 + class null_eq_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + explicit null_eq_node(expression_ptr branch, const bool equality = true) + : equality_(equality) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + + 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); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_nulleq; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bool equality_; + branch_t branch_; + }; + + template + class literal_node exprtk_final : public expression_node + { + public: + + explicit literal_node(const T& v) + : value_(v) + {} + + inline T value() const exprtk_override + { + return value_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_constant; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return reinterpret_cast*>(0); + } + + private: + + literal_node(const literal_node&) exprtk_delete; + literal_node& operator=(const literal_node&) exprtk_delete; + + const T value_; + }; + + template + struct range_pack; + + template + struct range_data_type; + + template + class range_interface + { + public: + + typedef range_pack range_t; + + virtual ~range_interface() {} + + virtual range_t& range_ref() = 0; + + virtual const range_t& range_ref() const = 0; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_base_node + { + public: + + typedef range_data_type range_data_type_t; + + virtual ~string_base_node() {} + + virtual std::string str () const = 0; + + virtual char_cptr base() const = 0; + + virtual std::size_t size() const = 0; + }; + + template + class string_literal_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef range_pack range_t; + + explicit string_literal_node(const std::string& v) + : value_(v) + { + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringconst; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return reinterpret_cast*>(0); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return value_.data(); + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + private: + + string_literal_node(const string_literal_node&) exprtk_delete; + string_literal_node& operator=(const string_literal_node&) exprtk_delete; + + const std::string value_; + range_t rp_; + }; + #endif + + template + class unary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + unary_node(const operator_type& opr, expression_ptr branch) + : operation_(opr) + { + construct_branch_pair(branch_,branch); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + + const T arg = branch_.first->value(); + + return numeric::process(operation_,arg); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_unary; + } + + inline operator_type operation() + { + return operation_; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + inline void release() + { + branch_.second = false; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_; + }; + + template + class binary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + binary_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : operation_(opr) + { + init_branches<2>(branch_, branch0, branch1); + } + + inline T value() const exprtk_override + { + assert(branch_[0].first); + assert(branch_[1].first); + + const T arg0 = branch_[0].first->value(); + const T arg1 = branch_[1].first->value(); + + return numeric::process(operation_,arg0,arg1); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_binary; + } + + inline operator_type operation() + { + return operation_; + } + + inline expression_node* branch(const std::size_t& index = 0) const exprtk_override + { + if (0 == index) + return branch_[0].first; + else if (1 == index) + return branch_[1].first; + else + return reinterpret_cast(0); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[2]; + }; + + template + class binary_ext_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + binary_ext_node(expression_ptr branch0, expression_ptr branch1) + { + init_branches<2>(branch_, branch0, branch1); + } + + inline T value() const exprtk_override + { + assert(branch_[0].first); + assert(branch_[1].first); + + const T arg0 = branch_[0].first->value(); + const T arg1 = branch_[1].first->value(); + + return Operation::process(arg0,arg1); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_binary_ext; + } + + inline operator_type operation() + { + return Operation::operation(); + } + + inline expression_node* branch(const std::size_t& index = 0) const exprtk_override + { + if (0 == index) + return branch_[0].first; + else if (1 == index) + return branch_[1].first; + else + return reinterpret_cast(0); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + + protected: + + branch_t branch_[2]; + }; + + template + class trinary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + assert(branch_[0].first); + assert(branch_[1].first); + assert(branch_[2].first); + + 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::quiet_NaN(); + } + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_trinary; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<3>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[3]; + }; + + template + class quaternary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_quaternary; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<4>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[4]; + }; + + template + class conditional_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + conditional_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + { + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_ , consequent ); + construct_branch_pair(alternative_, alternative); + } + + inline T value() const exprtk_override + { + assert(condition_ .first); + assert(consequent_ .first); + assert(alternative_.first); + + if (is_true(condition_)) + return consequent_.first->value(); + else + return alternative_.first->value(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_conditional; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + expression_node::ndb_t::collect(alternative_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth + (condition_, consequent_, alternative_); + } + + private: + + branch_t condition_; + branch_t consequent_; + branch_t alternative_; + }; + + template + class cons_conditional_node exprtk_final : public expression_node + { + public: + + // Consequent only conditional statement node + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + cons_conditional_node(expression_ptr condition, + expression_ptr consequent) + { + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_, consequent); + } + + inline T value() const exprtk_override + { + assert(condition_ .first); + assert(consequent_.first); + + if (is_true(condition_)) + return consequent_.first->value(); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_conditional; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t:: + compute_node_depth(condition_, consequent_); + } + + private: + + branch_t condition_; + branch_t consequent_; + }; + + #ifndef exprtk_disable_break_continue + template + class break_exception + { + public: + + explicit break_exception(const T& v) + : value(v) + {} + + T value; + }; + + class continue_exception {}; + + template + class break_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + break_node(expression_ptr ret = expression_ptr(0)) + { + construct_branch_pair(return_, ret); + } + + inline T value() const exprtk_override + { + const T result = return_.first ? + return_.first->value() : + std::numeric_limits::quiet_NaN(); + + throw break_exception(result); + + #ifndef _MSC_VER + return std::numeric_limits::quiet_NaN(); + #endif + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_break; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(return_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(return_); + } + + private: + + branch_t return_; + }; + + template + class continue_node exprtk_final : public expression_node + { + public: + + inline T value() const exprtk_override + { + throw continue_exception(); + #ifndef _MSC_VER + return std::numeric_limits::quiet_NaN(); + #endif + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_break; + } + }; + #endif + + struct loop_runtime_checker + { + loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check, + loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) + : 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_); + } + + inline void reset(const _uint64_t initial_value = 0) const + { + iteration_count_ = initial_value; + } + + inline bool check() const + { + if ( + (0 == loop_runtime_check_) || + (++iteration_count_ <= max_loop_iterations_) + ) + { + return true; + } + + loop_runtime_check::violation_context ctxt; + ctxt.loop = loop_type_; + 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_; + const details::_uint64_t& max_loop_iterations_; + loop_runtime_check::loop_types loop_type_; + }; + + template + class while_loop_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + while_loop_node(expression_ptr condition, + expression_ptr loop_body) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const exprtk_override + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + while (is_true(condition_)) + { + result = loop_body_.first->value(); + } + + return result; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_while; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + protected: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class while_loop_rtc_node exprtk_final + : public while_loop_node + , public loop_runtime_checker + { + public: + + typedef while_loop_node parent_t; + typedef expression_node* 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 + class repeat_until_loop_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + repeat_until_loop_node(expression_ptr condition, + expression_ptr loop_body) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const exprtk_override + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + do + { + result = loop_body_.first->value(); + } + while (is_false(condition_.first)); + + return result; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_repeat; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + protected: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class repeat_until_loop_rtc_node exprtk_final + : public repeat_until_loop_node + , public loop_runtime_checker + { + public: + + typedef repeat_until_loop_node parent_t; + typedef expression_node* 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 + class for_loop_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + for_loop_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body) + { + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); + } + + inline T value() const exprtk_override + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + if (initialiser_.first) + initialiser_.first->value(); + + if (incrementor_.first) + { + while (is_true(condition_)) + { + result = loop_body_.first->value(); + incrementor_.first->value(); + } + } + else + { + while (is_true(condition_)) + { + result = loop_body_.first->value(); + } + } + + return result; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_for; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_ , node_delete_list); + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(incrementor_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth + (initialiser_, condition_, incrementor_, loop_body_); + } + + protected: + + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; + }; + + template + class for_loop_rtc_node exprtk_final + : public for_loop_node + , public loop_runtime_checker + { + public: + + typedef for_loop_node parent_t; + typedef expression_node* expression_ptr; + + 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) + {} + + 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(); + + 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 + class while_loop_bc_node : public while_loop_node + { + public: + + typedef while_loop_node parent_t; + typedef expression_node* 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_)) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + + return result; + } + }; + + template + class while_loop_bc_rtc_node exprtk_final + : public while_loop_bc_node + , public loop_runtime_checker + { + public: + + typedef while_loop_bc_node parent_t; + typedef expression_node* expression_ptr; + + 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 + { + 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()) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + + return result; + } + }; + + template + class repeat_until_loop_bc_node : public repeat_until_loop_node + { + public: + + typedef repeat_until_loop_node parent_t; + typedef expression_node* expression_ptr; + + repeat_until_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); + + do + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + while (is_false(parent_t::condition_.first)); + + return result; + } + }; + + template + class repeat_until_loop_bc_rtc_node exprtk_final + : public repeat_until_loop_bc_node, + public loop_runtime_checker + { + public: + + typedef repeat_until_loop_bc_node parent_t; + typedef expression_node* expression_ptr; + + 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 + { + assert(parent_t::condition_.first); + assert(parent_t::loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + do + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); + + return result; + } + }; + + template + class for_loop_bc_node : public for_loop_node + { + public: + + typedef for_loop_node parent_t; + typedef expression_node* expression_ptr; + + for_loop_bc_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body) + : parent_t(initialiser, condition, incrementor, loop_body) + {} + + inline T value() const exprtk_override + { + assert(parent_t::condition_.first); + assert(parent_t::loop_body_.first); + + T result = T(0); + + if (parent_t::initialiser_.first) + parent_t::initialiser_.first->value(); + + if (parent_t::incrementor_.first) + { + while (is_true(parent_t::condition_)) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + + parent_t::incrementor_.first->value(); + } + } + else + { + while (is_true(parent_t::condition_)) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + } + + return result; + } + }; + + template + class for_loop_bc_rtc_node exprtk_final + : public for_loop_bc_node + , public loop_runtime_checker + { + public: + + typedef for_loop_bc_node parent_t; + typedef expression_node* 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) + {} + + 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(); + + 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& 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& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + } + + return result; + } + }; + #endif + + template + class switch_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit switch_node(const Sequence& 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; + } + } + } + + inline T value() const exprtk_override + { + 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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override exprtk_final + { + return expression_node::e_switch; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + protected: + + std::vector arg_list_; + }; + + template + class switch_n_node exprtk_final : public switch_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit switch_n_node(const Sequence& arg_list) + : switch_node(arg_list) + {} + + inline T value() const exprtk_override + { + return Switch_N::process(switch_node::arg_list_); + } + }; + + template + class multi_switch_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit multi_switch_node(const Sequence& 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; + } + } + } + + inline T value() const exprtk_override + { + T result = T(0); + + if (arg_list_.empty()) + { + return std::numeric_limits::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; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_mswitch; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + private: + + std::vector arg_list_; + }; + + template + class ivariable + { + public: + + virtual ~ivariable() {} + + virtual T& ref() = 0; + virtual const T& ref() const = 0; + }; + + template + class variable_node exprtk_final + : public expression_node, + public ivariable + { + public: + + static T null_value; + + explicit variable_node() + : value_(&null_value) + {} + + explicit variable_node(T& v) + : value_(&v) + {} + + inline bool operator <(const variable_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + return (*value_); + } + + inline T& ref() exprtk_override + { + return (*value_); + } + + inline const T& ref() const exprtk_override + { + return (*value_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_variable; + } + + private: + + T* value_; + }; + + template + T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + + template + struct range_pack + { + typedef expression_node* expression_node_ptr; + typedef std::pair cached_range_t; + + range_pack() + : n0_e (std::make_pair(false,expression_node_ptr(0))) + , n1_e (std::make_pair(false,expression_node_ptr(0))) + , n0_c (std::make_pair(false,0)) + , n1_c (std::make_pair(false,0)) + , cache(std::make_pair(0,0)) + {} + + void clear() + { + n0_e = std::make_pair(false,expression_node_ptr(0)); + n1_e = std::make_pair(false,expression_node_ptr(0)); + n0_c = std::make_pair(false,0); + n1_c = std::make_pair(false,0); + cache = std::make_pair(0,0); + } + + void free() + { + if (n0_e.first && n0_e.second) + { + n0_e.first = false; + + if ( + !is_variable_node(n0_e.second) && + !is_string_node (n0_e.second) + ) + { + destroy_node(n0_e.second); + } + } + + if (n1_e.first && n1_e.second) + { + n1_e.first = false; + + if ( + !is_variable_node(n1_e.second) && + !is_string_node (n1_e.second) + ) + { + destroy_node(n1_e.second); + } + } + } + + bool const_range() const + { + return ( n0_c.first && n1_c.first) && + (!n0_e.first && !n1_e.first); + } + + bool var_range() const + { + 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::max()) const + { + if (n0_c.first) + r0 = n0_c.second; + else if (n0_e.first) + { + r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); + } + else + return false; + + if (n1_c.first) + r1 = n1_c.second; + else if (n1_e.first) + { + r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); + } + else + return false; + + if ( + (std::numeric_limits::max() != size) && + (std::numeric_limits::max() == r1 ) + ) + { + r1 = size - 1; + } + + cache.first = r0; + cache.second = r1; + + #ifndef exprtk_enable_range_runtime_checks + return (r0 <= r1); + #else + return range_runtime_check(r0, r1, size); + #endif + } + + 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 n0_e; + std::pair n1_e; + std::pair n0_c; + std::pair n1_c; + mutable cached_range_t cache; + + #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 + }; + + template + class string_base_node; + + template + struct range_data_type + { + typedef range_pack range_t; + typedef string_base_node* strbase_ptr_t; + + range_data_type() + : range(0) + , data (0) + , size (0) + , type_size(0) + , str_node (0) + {} + + range_t* range; + void* data; + std::size_t size; + std::size_t type_size; + strbase_ptr_t str_node; + }; + + template class vector_node; + + template + class vector_interface + { + public: + + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + virtual ~vector_interface() {} + + virtual std::size_t size () const = 0; + + virtual vector_node_ptr vec() const = 0; + + virtual vector_node_ptr vec() = 0; + + virtual vds_t& vds () = 0; + + virtual const vds_t& vds () const = 0; + + virtual bool side_effect () const { return false; } + }; + + template + class vector_node exprtk_final + : public expression_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + explicit vector_node(vector_holder_t* vh) + : vector_holder_(vh) + , vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + vector_node(const vds_t& vds, vector_holder_t* vh) + : vector_holder_(vh) + , vds_(vds) + {} + + inline T value() const exprtk_override + { + return vds().data()[0]; + } + + vector_node_ptr vec() const exprtk_override + { + return const_cast(this); + } + + vector_node_ptr vec() exprtk_override + { + return this; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vector; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + vector_holder_t* vector_holder_; + vds_t vds_; + }; + + template + class vector_elem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; + + vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vec_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + { + construct_branch_pair(index_, index); + } + + inline T value() const exprtk_override + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline T& ref() exprtk_override + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline const T& ref() const exprtk_override + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vec_holder_); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(index_); + } + + private: + + vector_holder_ptr vec_holder_; + T* vector_base_; + branch_t index_; + }; + + template + class rebasevector_elem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair branch_t; + + rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) + , vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(index_, index); + } + + inline T value() const exprtk_override + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline T& ref() exprtk_override + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline const T& ref() const exprtk_override + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_rbvecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(index_); + } + + private: + + vector_holder_ptr vector_holder_; + vds_t vds_; + branch_t index_; + }; + + template + class rebasevector_celem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + + rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) + , vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + inline T value() const exprtk_override + { + return *(vds_.data() + index_); + } + + inline T& ref() exprtk_override + { + return *(vds_.data() + index_); + } + + inline const T& ref() const exprtk_override + { + return *(vds_.data() + index_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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 + class vector_assignment_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_assignment_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base) + , initialiser_list_(initialiser_list) + , size_(size) + , single_value_initialse_(single_value_initialse) + {} + + inline T value() const exprtk_override + { + if (single_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + else + { + const std::size_t initialiser_list_size = initialiser_list_.size(); + + for (std::size_t i = 0; i < initialiser_list_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (initialiser_list_size < size_) + { + for (std::size_t i = initialiser_list_size; i < size_; ++i) + { + *(vector_base_ + i) = T(0); + } + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecdefass; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_assignment_node(const vector_assignment_node&) exprtk_delete; + vector_assignment_node& operator=(const vector_assignment_node&) exprtk_delete; + + mutable T* vector_base_; + std::vector initialiser_list_; + const std::size_t size_; + const bool single_value_initialse_; + }; + + template + class swap_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef variable_node* variable_node_ptr; + + swap_node(variable_node_ptr var0, variable_node_ptr var1) + : var0_(var0) + , var1_(var1) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template + class swap_generic_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + typedef ivariable* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : binary_node(details::e_swap, var0, var1) + , var0_(dynamic_cast(var0)) + , var1_(dynamic_cast(var1)) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + }; + + template + class swap_vecvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node * vector_node_ptr; + typedef vec_data_store vds_t; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , vec_size_ (0) + , initialised_ (false) + { + if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } + } + + if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::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; + } + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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::quiet_NaN(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecvecswap; + } + + 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_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + std::size_t vec_size_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class stringvar_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + static std::string null_value; + + explicit stringvar_node() + : value_(&null_value) + {} + + explicit stringvar_node(std::string& v) + : value_(&v) + { + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline bool operator <(const stringvar_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + rp_.n1_c.second = (*value_).size() - 1; + rp_.cache.second = rp_.n1_c.second; + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return ref(); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + std::string& ref() + { + return (*value_); + } + + const std::string& ref() const + { + return (*value_); + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvar; + } + + void rebase(std::string& s) + { + value_ = &s; + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,value_->size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + private: + + std::string* value_; + mutable range_t rp_; + }; + + template + std::string stringvar_node::null_value = std::string(""); + + template + class string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + static std::string null_value; + + explicit string_range_node(std::string& v, const range_t& rp) + : value_(&v) + , rp_(rp) + {} + + virtual ~string_range_node() + { + rp_.free(); + } + + inline bool operator <(const string_range_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + inline std::string str() const exprtk_override + { + return (*value_); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + inline range_t range() const + { + return rp_; + } + + inline virtual std::string& ref() + { + return (*value_); + } + + inline virtual const std::string& ref() const + { + return (*value_); + } + + inline range_t& range_ref() exprtk_override + { + return rp_; + } + + inline const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvarrng; + } + + private: + + std::string* value_; + range_t rp_; + }; + + template + std::string string_range_node::null_value = std::string(""); + + template + class const_string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + explicit const_string_range_node(const std::string& v, const range_t& rp) + : value_(v) + , rp_(rp) + {} + + ~const_string_range_node() + { + rp_.free(); + } + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return value_.data(); + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t range() const + { + return rp_; + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_cstringvarrng; + } + + private: + + const_string_range_node(const const_string_range_node&) exprtk_delete; + const_string_range_node& operator=(const const_string_range_node&) exprtk_delete; + + const std::string value_; + range_t rp_; + }; + + template + class generic_string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef std::pair branch_t; + + generic_string_range_node(expression_ptr str_branch, const range_t& brange) + : initialised_(false) + , str_base_ptr_ (0) + , str_range_ptr_(0) + , base_range_(brange) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(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(branch_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(branch_.first); + + if (0 == str_range_ptr_) + return; + } + + initialised_ = (str_base_ptr_ && str_range_ptr_); + + assert(initialised_); + } + + ~generic_string_range_node() + { + base_range_.free(); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(branch_.first); + + 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; + + const range_t& range = str_range_ptr_->range_ref(); + + const std::size_t base_str_size = str_base_ptr_->size(); + + if ( + range (str_r0, str_r1, base_str_size) && + base_range_( r0, r1, base_str_size - str_r0) + ) + { + 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::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return &value_[0]; + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t& range_ref() exprtk_override + { + return range_; + } + + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strgenrange; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bool initialised_; + 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_; + }; + + template + class string_concat_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef range_t* range_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + string_concat_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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; + + const range_t& range0 = str0_range_ptr_->range_ref(); + const range_t& range1 = str1_range_ptr_->range_ref(); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = (str0_r1 - str0_r0) + 1; + const std::size_t size1 = (str1_r1 - str1_r0) + 1; + + value_.assign(str0_base_ptr_->base() + str0_r0, size0); + value_.append(str1_base_ptr_->base() + str1_r0, size1); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return &value_[0]; + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t& range_ref() exprtk_override + { + return range_; + } + + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strconcat; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; + }; + + template + class swap_string_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + + swap_string_node(expression_ptr branch0, expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1), + initialised_(false), + str0_node_ptr_(0), + str1_node_ptr_(0) + { + if (is_string_node(binary_node::branch_[0].first)) + { + str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + + if (is_string_node(binary_node::branch_[1].first)) + { + str1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + + initialised_ = (str0_node_ptr_ && str1_node_ptr_); + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return str0_node_ptr_->str(); + } + + char_cptr base() const exprtk_override + { + return str0_node_ptr_->base(); + } + + std::size_t size() const exprtk_override + { + return str0_node_ptr_->size(); + } + + range_t& range_ref() exprtk_override + { + return str0_node_ptr_->range_ref(); + } + + const range_t& range_ref() const exprtk_override + { + return str0_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strswap; + } + + private: + + bool initialised_; + strvar_node_ptr str0_node_ptr_; + strvar_node_ptr str1_node_ptr_; + }; + + template + class swap_genstrings_node exprtk_final : public binary_node + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + swap_genstrings_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_default, branch0, branch1) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + , initialised_(false) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::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_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = range0.cache_size(); + const std::size_t size1 = range1.cache_size(); + const std::size_t max_size = std::min(size0,size1); + + char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast(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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strswap; + } + + private: + + swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; + swap_genstrings_node& operator=(const swap_genstrings_node&) exprtk_delete; + + 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 + class stringvar_size_node exprtk_final : public expression_node + { + public: + + static std::string null_value; + + explicit stringvar_size_node() + : value_(&null_value) + {} + + explicit stringvar_size_node(std::string& v) + : value_(&v) + {} + + inline T value() const exprtk_override + { + return T((*value_).size()); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvarsize; + } + + private: + + std::string* value_; + }; + + template + std::string stringvar_size_node::null_value = std::string(""); + + template + class string_size_node exprtk_final : public expression_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef std::pair 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(branch_.first); + + if (0 == str_base_ptr_) + return; + } + } + + inline T value() const exprtk_override + { + T result = std::numeric_limits::quiet_NaN(); + + if (str_base_ptr_) + { + branch_.first->value(); + result = T(str_base_ptr_->size()); + } + + return result; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringsize; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 + class assignment_string_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + + assignment_string_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_node_ptr_ (0) + , str1_range_ptr_(0) + { + if (is_string_node(binary_node::branch_[0].first)) + { + str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::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_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[1].first->value(); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + const range_t& range = (*str1_range_ptr_); + + if (range(r0, r1, str1_base_ptr_->size())) + { + AssignmentProcess::execute(str0_node_ptr_->ref(), + str1_base_ptr_->base() + r0, + (r1 - r0) + 1); + + binary_node::branch_[0].first->value(); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return str0_node_ptr_->str(); + } + + char_cptr base() const exprtk_override + { + return str0_node_ptr_->base(); + } + + std::size_t size() const exprtk_override + { + return str0_node_ptr_->size(); + } + + range_t& range_ref() exprtk_override + { + return str0_node_ptr_->range_ref(); + } + + const range_t& range_ref() const exprtk_override + { + return str0_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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 + class assignment_string_range_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_range_node* str_rng_node_ptr; + typedef string_base_node * str_base_ptr; + + assignment_string_range_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(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) + { + if (is_string_range_node(binary_node::branch_[0].first)) + { + str0_rng_node_ptr_ = static_cast(binary_node::branch_[0].first); + + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::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_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(s0_r0, s0_r1, str0_base_ptr_->size()) && + range1(s1_r0, s1_r1, str1_base_ptr_->size()) + ) + { + 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(base() + s0_r0)); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return str0_base_ptr_->str(); + } + + char_cptr base() const exprtk_override + { + return str0_base_ptr_->base(); + } + + std::size_t size() const exprtk_override + { + return str0_base_ptr_->size(); + } + + range_t& range_ref() exprtk_override + { + return str0_rng_node_ptr_->range_ref(); + } + + const range_t& range_ref() const exprtk_override + { + return str0_rng_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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 + class conditional_string_node exprtk_final + : public trinary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + conditional_string_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + : trinary_node(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) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(trinary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(trinary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(condition_ ); + assert(consequent_ ); + assert(alternative_); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (is_true(condition_)) + { + consequent_->value(); + + const range_t& range = str0_range_ptr_->range_ref(); + + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } + else + { + alternative_->value(); + + const range_t& range = str1_range_ptr_->range_ref(); + + if (range(r0, r1, str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str1_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(0); + } + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return &value_[0]; + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t& range_ref() exprtk_override + { + return range_; + } + + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strcondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr condition_; + expression_ptr consequent_; + expression_ptr alternative_; + }; + + template + class cons_conditional_str_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + cons_conditional_str_node(expression_ptr condition, + expression_ptr consequent) + : binary_node(details::e_default, consequent, condition) + , initialised_(false) + , str0_base_ptr_ (0) + , str0_range_ptr_(0) + , condition_ (condition ) + , consequent_(consequent) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && str0_range_ptr_ ; + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(condition_ ); + assert(consequent_); + + if (is_true(condition_)) + { + consequent_->value(); + + const range_t& range = str0_range_ptr_->range_ref(); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } + } + + return std::numeric_limits::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_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strccondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + irange_ptr str0_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr condition_; + expression_ptr consequent_; + }; + + template + class str_vararg_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit str_vararg_node(const Sequence& arg_list) + : initialised_(false) + , str_base_ptr_ (0) + , str_range_ptr_(0) + { + construct_branch_pair(final_node_, const_cast(arg_list.back())); + + if (0 == final_node_.first) + return; + else if (!is_generally_string_node(final_node_.first)) + return; + + str_base_ptr_ = dynamic_cast(final_node_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(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; + } + } + } + } + + inline T value() const exprtk_override + { + if (!arg_list_.empty()) + { + VarArgFunction::process(arg_list_); + } + + final_node_.first->value(); + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return str_base_ptr_->str(); + } + + char_cptr base() const exprtk_override + { + return str_base_ptr_->base(); + } + + std::size_t size() const exprtk_override + { + return str_base_ptr_->size(); + } + + range_t& range_ref() exprtk_override + { + return str_range_ptr_->range_ref(); + } + + const range_t& range_ref() const exprtk_override + { + return str_range_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvararg; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(final_node_ , node_delete_list); + expression_node::ndb_t::collect(arg_list_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return std::max( + expression_node::ndb_t::compute_node_depth(final_node_), + expression_node::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 arg_list_; + }; + #endif + + template + inline T axn(const T a, const T x) + { + // a*x^n + return a * exprtk::details::numeric::fast_exp::result(x); + } + + template + inline T axnb(const T a, const T x, const T b) + { + // a*x^n+b + return a * exprtk::details::numeric::fast_exp::result(x) + b; + } + + template + struct sf_base + { + typedef typename details::functor_t::Type Type; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + }; + + #define define_sfop3(NN, OP0, OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::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(x,y,z))," ") + define_sfop3(32,(axnb(x,y,z))," ") + define_sfop3(33,(axnb(x,y,z))," ") + define_sfop3(34,(axnb(x,y,z))," ") + define_sfop3(35,(axnb(x,y,z))," ") + define_sfop3(36,(axnb(x,y,z))," ") + define_sfop3(37,(axnb(x,y,z))," ") + define_sfop3(38,(axnb(x,y,z))," ") + define_sfop3(39,x * numeric::log(y) + z,"") + define_sfop3(40,x * numeric::log(y) - z,"") + define_sfop3(41,x * numeric::log10(y) + z,"") + define_sfop3(42,x * numeric::log10(y) - z,"") + define_sfop3(43,x * numeric::sin(y) + z ,"") + define_sfop3(44,x * numeric::sin(y) - z ,"") + define_sfop3(45,x * numeric::cos(y) + z ,"") + define_sfop3(46,x * numeric::cos(y) - z ,"") + define_sfop3(47,details::is_true(x) ? y : z,"") + + #define define_sfop4(NN, OP0, OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::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(x,y) + axn(z,w)),"") + define_sfop4(85,(axn(x,y) + axn(z,w)),"") + define_sfop4(86,(axn(x,y) + axn(z,w)),"") + define_sfop4(87,(axn(x,y) + axn(z,w)),"") + define_sfop4(88,(axn(x,y) + axn(z,w)),"") + define_sfop4(89,(axn(x,y) + axn(z,w)),"") + define_sfop4(90,(axn(x,y) + axn(z,w)),"") + define_sfop4(91,(axn(x,y) + axn(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 + class sf3_node exprtk_final : public trinary_node + { + public: + + typedef expression_node* expression_ptr; + + sf3_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2) + : trinary_node(opr, branch0, branch1, branch2) + {} + + inline T value() const exprtk_override + { + assert(trinary_node::branch_[0].first); + assert(trinary_node::branch_[1].first); + assert(trinary_node::branch_[2].first); + + const T x = trinary_node::branch_[0].first->value(); + const T y = trinary_node::branch_[1].first->value(); + const T z = trinary_node::branch_[2].first->value(); + + return SpecialFunction::process(x, y, z); + } + }; + + template + class sf4_node exprtk_final : public quaternary_node + { + public: + + typedef expression_node* expression_ptr; + + sf4_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2, + expression_ptr branch3) + : quaternary_node(opr, branch0, branch1, branch2, branch3) + {} + + inline T value() const exprtk_override + { + assert(quaternary_node::branch_[0].first); + assert(quaternary_node::branch_[1].first); + assert(quaternary_node::branch_[2].first); + assert(quaternary_node::branch_[3].first); + + const T x = quaternary_node::branch_[0].first->value(); + const T y = quaternary_node::branch_[1].first->value(); + const T z = quaternary_node::branch_[2].first->value(); + const T w = quaternary_node::branch_[3].first->value(); + + return SpecialFunction::process(x, y, z, w); + } + }; + + template + class sf3_var_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf3_var_node(const T& v0, const T& v1, const T& v2) + : v0_(v0) + , v1_(v1) + , v2_(v2) + {} + + inline T value() const exprtk_override + { + return SpecialFunction::process(v0_, v1_, v2_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_trinary; + } + + private: + + sf3_var_node(const sf3_var_node&) exprtk_delete; + sf3_var_node& operator=(const sf3_var_node&) exprtk_delete; + + const T& v0_; + const T& v1_; + const T& v2_; + }; + + template + class sf4_var_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) + : v0_(v0) + , v1_(v1) + , v2_(v2) + , v3_(v3) + {} + + inline T value() const exprtk_override + { + return SpecialFunction::process(v0_, v1_, v2_, v3_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_trinary; + } + + private: + + sf4_var_node(const sf4_var_node&) exprtk_delete; + sf4_var_node& operator=(const sf4_var_node&) exprtk_delete; + + const T& v0_; + const T& v1_; + const T& v2_; + const T& v3_; + }; + + template + class vararg_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit vararg_node(const Sequence& 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; + } + } + } + + inline T value() const exprtk_override + { + return VarArgFunction::process(arg_list_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vararg; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + private: + + std::vector arg_list_; + }; + + template + class vararg_varnode exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit vararg_varnode(const Sequence& 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* var_node_ptr = static_cast*>(arg_list[i]); + arg_list_[i] = (&var_node_ptr->ref()); + } + else + { + arg_list_.clear(); + return; + } + } + } + + inline T value() const exprtk_override + { + if (!arg_list_.empty()) + return VarArgFunction::process(arg_list_); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vararg; + } + + private: + + std::vector arg_list_; + }; + + template + class vectorize_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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*>(v_.first); + } + else + ivec_ptr_ = 0; + } + + inline T value() const exprtk_override + { + if (ivec_ptr_) + { + assert(v_.first); + + v_.first->value(); + + return VecFunction::process(ivec_ptr_); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecfunc; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(v_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(v_); + } + + private: + + vector_interface* ivec_ptr_; + branch_t v_; + }; + + template + class assignment_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , var_node_ptr_(0) + { + if (is_variable_node(binary_node::branch_[0].first)) + { + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (var_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = var_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + variable_node* var_node_ptr_; + }; + + template + class assignment_vec_elem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_vec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = vec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const exprtk_override + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + const T v = binary_node::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::quiet_NaN(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecvalass; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_(false) + , src_is_ivec_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::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_); + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[1].first); + + binary_node::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::quiet_NaN(); + } + + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecvecass; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + bool src_is_ivec_; + vds_t vds_; + }; + + template + class assignment_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , var_node_ptr_(0) + { + if (is_variable_node(binary_node::branch_[0].first)) + { + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (var_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = var_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + variable_node* var_node_ptr_; + }; + + template + class assignment_vec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_vec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const exprtk_override + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_op_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const exprtk_override + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + const T v = binary_node::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::quiet_NaN(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecopvalass; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + bool side_effect() const exprtk_override + { + return true; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_op_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_->vds() = vds(); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::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_); + + assert(initialised_); + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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::quiet_NaN(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecopvecass; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + bool side_effect() const exprtk_override + { + return true; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + template + class vec_binop_vecvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , temp_ (0) + , temp_vec_node_(0) + , initialised_(false) + { + bool v0_is_ivec = false; + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + else if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; + } + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; + } + } + + if (vec0_node_ptr_ && vec1_node_ptr_) + { + vector_holder& vec0 = vec0_node_ptr_->vec_holder(); + vector_holder& 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(vds().data(),vds().size()); + temp_vec_node_ = new vector_node (vds(),temp_); + + initialised_ = true; + } + + assert(initialised_); + } + + ~vec_binop_vecvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const exprtk_override + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::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::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::node_type type() const exprtk_override + { + return expression_node::e_vecvecarith; + } + + std::size_t size() const exprtk_override + { + return vds_.size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + 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 + class vec_binop_vecval_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecval_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec0_node_ptr_(0) + , temp_ (0) + , temp_vec_node_(0) + { + bool v0_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + else if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::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(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~vec_binop_vecval_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const exprtk_override + { + if (vec0_node_ptr_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + const T v = binary_node::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::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::node_type type() const exprtk_override + { + return expression_node::e_vecvalarith; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class vec_binop_valvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_valvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec1_node_ptr_(0) + , temp_ (0) + , temp_vec_node_(0) + { + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::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(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~vec_binop_valvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const exprtk_override + { + if (vec1_node_ptr_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + const T v = binary_node::branch_[0].first->value(); + binary_node::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::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::node_type type() const exprtk_override + { + return expression_node::e_vecvalarith; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node_ptr vec1_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class unary_vector_node exprtk_final + : public unary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + unary_vector_node(const operator_type& opr, expression_ptr branch0) + : unary_node(opr, branch0) + , vec0_node_ptr_(0) + , temp_ (0) + , temp_vec_node_(0) + { + bool vec0_is_ivec = false; + + if (is_vector_node(unary_node::branch_.first)) + { + vec0_node_ptr_ = static_cast(unary_node::branch_.first); + } + else if (is_ivector_node(unary_node::branch_.first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(unary_node::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(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~unary_vector_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const exprtk_override + { + assert(unary_node::branch_.first); + + unary_node::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::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::node_type type() const exprtk_override + { + return expression_node::e_vecunaryop; + } + + std::size_t size() const exprtk_override + { + return vds().size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class conditional_vector_node exprtk_final + : public expression_node + , public vector_interface + { + public: + + typedef expression_node * expression_ptr; + typedef vector_interface* vec_interface_ptr; + typedef vector_node * vector_node_ptr; + typedef vector_holder * vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair 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(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(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(vds_); + temp_vec_node_ = new vector_node (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::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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + expression_node::ndb_t::collect(alternative_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 + class scand_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + scand_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + {} + + inline T value() const exprtk_override + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + return ( + std::not_equal_to() + (T(0),binary_node::branch_[0].first->value()) && + std::not_equal_to() + (T(0),binary_node::branch_[1].first->value()) + ) ? T(1) : T(0); + } + }; + + template + class scor_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + scor_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + {} + + inline T value() const exprtk_override + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + return ( + std::not_equal_to() + (T(0),binary_node::branch_[0].first->value()) || + std::not_equal_to() + (T(0),binary_node::branch_[1].first->value()) + ) ? T(1) : T(0); + } + }; + + template + class function_N_node exprtk_final : public expression_node + { + public: + + // Function of N paramters. + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef IFunction ifunction; + + explicit function_N_node(ifunction* func) + : function_((N == func->param_count) ? func : reinterpret_cast(0)) + , parameter_count_(func->param_count) + {} + + template + 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& fn) const + { + return this < (&fn); + } + + inline T value() const exprtk_override + { + // 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::quiet_NaN(); + else + { + T v[N]; + evaluate_branches::execute(v,branch_); + return invoke::execute(*function_,v); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_function; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::template compute_node_depth(branch_); + } + + template + 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 + struct evaluate_branches + { + 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 + struct evaluate_branches + { + 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 + struct evaluate_branches + { + 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 + struct evaluate_branches + { + 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 + struct evaluate_branches + { + static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) + { + v[0] = b[0].first->value(); + } + }; + + template + struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits::quiet_NaN(); } }; + + template + struct invoke + { + 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 + struct invoke + { + 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 + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[18]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[17]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[16]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[15]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[14]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[13]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[12]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[11]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[10]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[9]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[8]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[7]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[6]) + { return f(v[0], v[1], v[2], v[3], v[4], v[5]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[5]) + { return f(v[0], v[1], v[2], v[3], v[4]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[4]) + { return f(v[0], v[1], v[2], v[3]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[3]) + { return f(v[0], v[1], v[2]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[2]) + { return f(v[0], v[1]); } + }; + + template + struct invoke + { + 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 + class function_N_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef IFunction ifunction; + + explicit function_N_node(ifunction* func) + : function_((0 == func->param_count) ? func : reinterpret_cast(0)) + {} + + inline bool operator <(const function_N_node& fn) const + { + return this < (&fn); + } + + inline T value() const exprtk_override + { + if (function_) + return (*function_)(); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_function; + } + + private: + + ifunction* function_; + }; + + template + class vararg_function_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vararg_function_node(VarArgFunction* func, + const std::vector& arg_list) + : function_(func) + , arg_list_(arg_list) + { + value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); + } + + inline bool operator <(const vararg_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const exprtk_override + { + if (function_) + { + populate_value_list(); + return (*function_)(value_list_); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vafunction; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + 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]); + } + } + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 arg_list_; + mutable std::vector value_list_; + }; + + template + class generic_function_node : public expression_node + { + public: + + typedef type_store type_store_t; + typedef expression_node* expression_ptr; + typedef variable_node variable_node_t; + typedef vector_node vector_node_t; + typedef variable_node_t* variable_node_ptr_t; + typedef vector_node_t* vector_node_ptr_t; + typedef range_interface range_interface_t; + typedef range_data_type range_data_type_t; + typedef typename range_interface::range_t range_t; + + typedef std::pair branch_t; + typedef std::pair void_t; + + typedef std::vector tmp_vs_t; + typedef std::vector typestore_list_t; + typedef std::vector range_list_t; + + explicit generic_function_node(const std::vector& arg_list, + GenericFunction* func = reinterpret_cast(0)) + : function_(func) + , arg_list_(arg_list) + {} + + virtual ~generic_function_node() {} + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override exprtk_final + { + return expression_node::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()); + branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast(0),false)); + + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + type_store_t& ts = typestore_list_[i]; + + if (0 == arg_list_[i]) + return false; + else if (is_ivector_node(arg_list_[i])) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 == (vi = dynamic_cast*>(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* sbn = reinterpret_cast*>(0); + + if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) + return false; + + ts.size = sbn->size(); + ts.data = reinterpret_cast(const_cast(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(0); + + if (0 == (ri = dynamic_cast(arg_list_[i]))) + return false; + + const range_t& rp = ri->range_ref(); + + if ( + rp.const_range() && + is_const_string_range_node(arg_list_[i]) + ) + { + ts.size = rp.const_size(); + ts.data = static_cast(ts.data) + rp.n0_c.second; + range_list_[i].range = reinterpret_cast(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(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(&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& fn) const + { + return this < (&fn); + } + + inline T value() const exprtk_override + { + 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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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) + { + const range_t& rp = (*rdt.range); + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp(r0, r1, rdt.size)) + { + type_store_t& ts = typestore_list_[i]; + + ts.size = rp.cache_size(); + #ifndef exprtk_disable_string_capabilities + if (ts.type == type_store_t::e_string) + ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; + else + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + } + else + return false; + } + } + + return true; + } + + GenericFunction* function_; + mutable typestore_list_t typestore_list_; + + private: + + std::vector arg_list_; + std::vector branch_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_function_node : public generic_function_node, + public string_base_node, + public range_interface + { + public: + + typedef generic_function_node gen_function_t; + typedef typename range_interface::range_t range_t; + + string_function_node(StringFunction* func, + const std::vector& arg_list) + : gen_function_t(arg_list,func) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + } + + inline bool operator <(const string_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const exprtk_override + { + 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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strfunction; + } + + std::string str() const exprtk_override + { + return ret_string_; + } + + char_cptr base() const exprtk_override + { + return &ret_string_[0]; + } + + std::size_t size() const exprtk_override + { + return ret_string_.size(); + } + + range_t& range_ref() exprtk_override + { + return range_; + } + + const range_t& range_ref() const exprtk_override + { + return range_; + } + + protected: + + mutable range_t range_; + mutable std::string ret_string_; + }; + #endif + + template + class multimode_genfunction_node : public generic_function_node + { + public: + + typedef generic_function_node gen_function_t; + typedef typename gen_function_t::range_t range_t; + + multimode_genfunction_node(GenericFunction* func, + const std::size_t& param_seq_index, + const std::vector& arg_list) + : gen_function_t(arg_list,func) + , param_seq_index_(param_seq_index) + {} + + inline T value() const exprtk_override + { + 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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override exprtk_final + { + return expression_node::e_genfunction; + } + + private: + + std::size_t param_seq_index_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class multimode_strfunction_node exprtk_final : public string_function_node + { + public: + + typedef string_function_node str_function_t; + typedef typename str_function_t::range_t range_t; + + multimode_strfunction_node(StringFunction* func, + const std::size_t& param_seq_index, + const std::vector& arg_list) + : str_function_t(func,arg_list) + , param_seq_index_(param_seq_index) + {} + + inline T value() const exprtk_override + { + 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::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strfunction; + } + + private: + + const std::size_t param_seq_index_; + }; + #endif + + class return_exception + {}; + + template + class null_igenfunc + { + public: + + virtual ~null_igenfunc() {} + + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + inline virtual T operator() (parameter_list_t) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + #ifndef exprtk_disable_return_statement + template + class return_node exprtk_final : public generic_function_node > + { + public: + + typedef results_context results_context_t; + typedef null_igenfunc igeneric_function_t; + typedef igeneric_function_t* igeneric_function_ptr; + typedef generic_function_node gen_function_t; + + return_node(const std::vector& arg_list, + results_context_t& rc) + : gen_function_t (arg_list) + , results_context_(&rc) + {} + + inline T value() const exprtk_override + { + if ( + (0 != results_context_) && + gen_function_t::populate_value_list() + ) + { + typedef typename type_store::parameter_list parameter_list_t; + + results_context_-> + assign(parameter_list_t(gen_function_t::typestore_list_)); + + throw return_exception(); + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_return; + } + + private: + + results_context_t* results_context_; + }; + + template + class return_envelope_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef results_context results_context_t; + typedef std::pair branch_t; + + return_envelope_node(expression_ptr body, results_context_t& rc) + : results_context_(&rc ) + , return_invoked_ (false) + { + construct_branch_pair(body_, body); + } + + inline T value() const exprtk_override + { + assert(body_.first); + + try + { + return_invoked_ = false; + results_context_->clear(); + + return body_.first->value(); + } + catch(const return_exception&) + { + return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); + } + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_retenv; + } + + inline bool* retinvk_ptr() + { + return &return_invoked_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(body_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 \ + struct OpName##_op \ + { \ + typedef typename functor_t::Type Type; \ + typedef typename expression_node::node_type node_t; \ + \ + static inline T process(Type v) \ + { \ + return numeric:: OpName (v); \ + } \ + \ + static inline node_t type() \ + { \ + return expression_node::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 + struct opr_base + { + typedef typename details::functor_t::Type Type; + typedef typename details::functor_t::RefType RefType; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + }; + + template + struct add_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::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::node_type type() { return expression_node::e_add; } + static inline details::operator_type operation() { return details::e_add; } + }; + + template + struct mul_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::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::node_type type() { return expression_node::e_mul; } + static inline details::operator_type operation() { return details::e_mul; } + }; + + template + struct sub_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::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::node_type type() { return expression_node::e_sub; } + static inline details::operator_type operation() { return details::e_sub; } + }; + + template + struct div_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::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::node_type type() { return expression_node::e_div; } + static inline details::operator_type operation() { return details::e_div; } + }; + + template + struct mod_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_mod; } + static inline details::operator_type operation() { return details::e_mod; } + }; + + template + struct pow_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_pow; } + static inline details::operator_type operation() { return details::e_pow; } + }; + + template + struct lt_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_lt; } + static inline details::operator_type operation() { return details::e_lt; } + }; + + template + struct lte_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_lte; } + static inline details::operator_type operation() { return details::e_lte; } + }; + + template + struct gt_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_gt; } + static inline details::operator_type operation() { return details::e_gt; } + }; + + template + struct gte_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_gte; } + static inline details::operator_type operation() { return details::e_gte; } + }; + + template + struct eq_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_eq; } + }; + + template + struct equal_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_equal; } + }; + + template + struct ne_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ne; } + static inline details::operator_type operation() { return details::e_ne; } + }; + + template + struct and_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_and; } + static inline details::operator_type operation() { return details::e_and; } + }; + + template + struct nand_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_nand; } + static inline details::operator_type operation() { return details::e_nand; } + }; + + template + struct or_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_or; } + static inline details::operator_type operation() { return details::e_or; } + }; + + template + struct nor_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_nor; } + }; + + template + struct xor_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xor; } + }; + + template + struct xnor_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xnor; } + }; + + template + struct in_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::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::node_type type() { return expression_node::e_in; } + static inline details::operator_type operation() { return details::e_in; } + }; + + template + struct like_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::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::node_type type() { return expression_node::e_like; } + static inline details::operator_type operation() { return details::e_like; } + }; + + template + struct ilike_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::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::node_type type() { return expression_node::e_ilike; } + static inline details::operator_type operation() { return details::e_ilike; } + }; + + template + struct inrange_op : public opr_base + { + typedef typename opr_base::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::node_type type() { return expression_node::e_inranges; } + static inline details::operator_type operation() { return details::e_inrange; } + }; + + template + inline T value(details::expression_node* n) + { + return n->value(); + } + + template + inline T value(std::pair*,bool> n) + { + return n.first->value(); + } + + template + inline T value(const T* t) + { + return (*t); + } + + template + inline T value(const T& t) + { + return t; + } + + template + struct vararg_add_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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 + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) ; + } + + template + 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 + 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 + struct vararg_mul_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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 + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) ; + } + + template + 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 + 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 + struct vararg_avg_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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::process(arg_list) / arg_list.size(); + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return (value(arg_list[0]) + value(arg_list[1])) / T(2); + } + + template + 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 + 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 + 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 + struct vararg_min_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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 + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return std::min(value(arg_list[0]),value(arg_list[1])); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return std::min( + std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return std::min( + std::min(std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))), + value(arg_list[4])); + } + }; + + template + struct vararg_max_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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 + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return std::max(value(arg_list[0]),value(arg_list[1])); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return std::max( + std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return std::max( + std::max(std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))), + value(arg_list[4])); + } + }; + + template + struct vararg_mand_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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(0), value(arg_list[i]))) + return T(0); + } + + return T(1); + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return std::not_equal_to() + (T(0), value(arg_list[0])) ? T(1) : T(0); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) + ) ? T(1) : T(0); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) + ) ? T(1) : T(0); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) + ) ? T(1) : T(0); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) && + std::not_equal_to()(T(0), value(arg_list[4])) + ) ? T(1) : T(0); + } + }; + + template + struct vararg_mor_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& 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(0), value(arg_list[i]))) + return T(1); + } + + return T(0); + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return std::not_equal_to() + (T(0), value(arg_list[0])) ? T(1) : T(0); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) + ) ? T(1) : T(0); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) + ) ? T(1) : T(0); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) + ) ? T(1) : T(0); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) || + std::not_equal_to()(T(0), value(arg_list[4])) + ) ? T(1) : T(0); + } + }; + + template + struct vararg_multi_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return std::numeric_limits::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 + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + value(arg_list[0]); + return value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + return value(arg_list[2]); + } + + template + 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 + 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 + 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 + 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 + 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 + struct vec_add_op + { + typedef vector_interface* 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(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 + struct vec_mul_op + { + typedef vector_interface* 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(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 + struct vec_avg_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const std::size_t vec_size = v->vec()->vds().size(); + + return vec_add_op::process(v) / vec_size; + } + }; + + template + struct vec_min_op + { + typedef vector_interface* 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 + struct vec_max_op + { + typedef vector_interface* 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 + class vov_base_node : public expression_node + { + public: + + virtual ~vov_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v0() const = 0; + + virtual const T& v1() const = 0; + }; + + template + class cov_base_node : public expression_node + { + public: + + virtual ~cov_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class voc_base_node : public expression_node + { + public: + + virtual ~voc_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class vob_base_node : public expression_node + { + public: + + virtual ~vob_base_node() {} + + virtual const T& v() const = 0; + }; + + template + class bov_base_node : public expression_node + { + public: + + virtual ~bov_base_node() {} + + virtual const T& v() const = 0; + }; + + template + class cob_base_node : public expression_node + { + public: + + virtual ~cob_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class boc_base_node : public expression_node + { + public: + + virtual ~boc_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class uv_base_node : public expression_node + { + public: + + virtual ~uv_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v() const = 0; + }; + + template + class sos_base_node : public expression_node + { + public: + + virtual ~sos_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class sosos_base_node : public expression_node + { + public: + + virtual ~sosos_base_node() {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class T0oT1oT2_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2_base_node() {} + + virtual std::string type_id() const = 0; + }; + + template + class T0oT1oT2oT3_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2oT3_base_node() {} + + virtual std::string type_id() const = 0; + }; + + template + class unary_variable_node exprtk_final : public uv_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + explicit unary_variable_node(const T& var) + : v_(var) + {} + + inline T value() const exprtk_override + { + return Operation::process(v_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T& v() const exprtk_override + { + return v_; + } + + private: + + unary_variable_node(const unary_variable_node&) exprtk_delete; + unary_variable_node& operator=(const unary_variable_node&) exprtk_delete; + + const T& v_; + }; + + template + class uvouv_node exprtk_final : public expression_node + { + public: + + // UOpr1(v0) Op UOpr2(v1) + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::ufunc_t ufunc_t; + typedef expression_node* expression_ptr; + + explicit uvouv_node(const T& var0,const T& var1, + ufunc_t uf0, ufunc_t uf1, bfunc_t bf) + : v0_(var0) + , v1_(var1) + , u0_(uf0 ) + , u1_(uf1 ) + , f_ (bf ) + {} + + inline T value() const exprtk_override + { + return f_(u0_(v0_),u1_(v1_)); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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: + + uvouv_node(const uvouv_node&) exprtk_delete; + uvouv_node& operator=(const uvouv_node&) exprtk_delete; + + const T& v0_; + const T& v1_; + const ufunc_t u0_; + const ufunc_t u1_; + const bfunc_t f_; + }; + + template + class unary_branch_node exprtk_final : public expression_node + { + public: + + typedef Operation operation_t; + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + explicit unary_branch_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const exprtk_override + { + return Operation::process(branch_.first->value()); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() + { + return Operation::operation(); + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + inline void release() + { + branch_.second = false; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + unary_branch_node(const unary_branch_node&) exprtk_delete; + unary_branch_node& operator=(const unary_branch_node&) exprtk_delete; + + branch_t branch_; + }; + + template struct is_const { enum {result = 0}; }; + template struct is_const { enum {result = 1}; }; + template struct is_const_ref { enum {result = 0}; }; + template struct is_const_ref { enum {result = 1}; }; + template struct is_ref { enum {result = 0}; }; + template struct is_ref { enum {result = 1}; }; + template struct is_ref { enum {result = 0}; }; + + template + 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::result>::result() \ + + template + struct T0oT1oT2process + { + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + + struct mode0 + { + static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) + { + // (T0 o0 T1) o1 T2 + return bf1(bf0(t0,t1),t2); + } + + template + 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 + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + ")" ; + return result; + } + }; + }; + + template + struct T0oT1oT20T3process + { + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + + struct mode0 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // (T0 o0 T1) o1 (T2 o2 T3) + return bf1(bf0(t0,t1),bf2(t2,t3)); + } + + template + 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 + 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 + 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 + 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 + 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 + struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_, T1_, v_) \ + template \ + struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: 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 + struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_, T1_, T2_, v_) \ + template \ + struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: 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 + struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_) \ + template \ + struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: 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 + class T0oT1 exprtk_final : public expression_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0oT1 node_type; + + T0oT1(T0 p0, T1 p1, const bfunc_t p2) + : t0_(p0) + , t1_(p1) + , f_ (p2) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1::result; + return result; + } + + inline operator_type operation() const exprtk_override + { + return e_default; + } + + inline T value() const exprtk_override + { + return f_(t0_,t1_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline bfunc_t f() const + { + return f_; + } + + template + static inline expression_node* allocate(Allocator& allocator, + T0 p0, T1 p1, + bfunc_t p2) + { + return allocator + .template allocate_type + (p0, p1, p2); + } + + private: + + T0oT1(const T0oT1&) exprtk_delete; + T0oT1& operator=(const T0oT1&) { return (*this); } + + T0 t0_; + T1 t1_; + const bfunc_t f_; + }; + + template + class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0oT1oT2 node_type; + typedef ProcessMode process_mode_t; + + T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , f0_(p3) + , f1_(p4) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() + { + return e_default; + } + + inline T value() const exprtk_override + { + return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + bfunc_t f0() const + { + return f0_; + } + + bfunc_t f1() const + { + return f1_; + } + + std::string type_id() const exprtk_override + { + return id(); + } + + static inline std::string id() + { + return process_mode_t::template id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) + { + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); + } + + private: + + T0oT1oT2(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + const bfunc_t f0_; + const bfunc_t f1_; + }; + + template + class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0_ T0; + typedef T1_ T1; + typedef T2_ T2; + typedef T3_ T3; + typedef T0oT1oT2oT3 node_type; + typedef ProcessMode process_mode_t; + + T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) + , f0_(p4) + , f1_(p5) + , f2_(p6) + {} + + inline T value() const exprtk_override + { + return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + inline T3 t3() const + { + return t3_; + } + + inline bfunc_t f0() const + { + return f0_; + } + + inline bfunc_t f1() const + { + return f1_; + } + + inline bfunc_t f2() const + { + return f2_; + } + + inline std::string type_id() const exprtk_override + { + return id(); + } + + static inline std::string id() + { + return process_mode_t::template id(); + } + + template + static inline expression_node* 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 + (p0, p1, p2, p3, p4, p5, p6); + } + + private: + + T0oT1oT2oT3(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + const bfunc_t f0_; + const bfunc_t f1_; + const bfunc_t f2_; + }; + + template + class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::tfunc_t tfunc_t; + typedef T value_type; + typedef T0oT1oT2_sf3 node_type; + + T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , f_ (p3) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() const exprtk_override + { + return e_default; + } + + inline T value() const exprtk_override + { + 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 + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) + { + return allocator + .template allocate_type + (p0, p1, p2, p3); + } + + private: + + T0oT1oT2_sf3(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + const tfunc_t f_; + }; + + template + class sf3ext_type_node : public T0oT1oT2_base_node + { + public: + + virtual ~sf3ext_type_node() {} + + virtual T0 t0() const = 0; + + virtual T1 t1() const = 0; + + virtual T2 t2() const = 0; + }; + + template + class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node + { + public: + + typedef T value_type; + typedef T0oT1oT2_sf3ext node_type; + + T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) + : t0_(p0) + , t1_(p1) + , t2_(p2) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() + { + return e_default; + } + + inline T value() const exprtk_override + { + return SF3Operation::process(t0_, t1_, t2_); + } + + T0 t0() const exprtk_override + { + return t0_; + } + + T1 t1() const exprtk_override + { + return t1_; + } + + T2 t2() const exprtk_override + { + return t2_; + } + + std::string type_id() const exprtk_override + { + return id(); + } + + static inline std::string id() + { + return SF3Operation::id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) + { + return allocator + .template allocate_type + (p0, p1, p2); + } + + private: + + T0oT1oT2_sf3ext(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + }; + + template + inline bool is_sf3ext_node(const expression_node* n) + { + switch (n->type()) + { + case expression_node::e_vovov : return true; + case expression_node::e_vovoc : return true; + case expression_node::e_vocov : return true; + case expression_node::e_covov : return true; + case expression_node::e_covoc : return true; + default : return false; + } + } + + template + class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t qfunc_t; + typedef T value_type; + typedef T0oT1oT2oT3_sf4 node_type; + + T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) + , f_ (p4) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; + return result; + } + + inline operator_type operation() const exprtk_override + { + return e_default; + } + + inline T value() const exprtk_override + { + 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 + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) + { + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); + } + + private: + + T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + const qfunc_t f_; + }; + + template + class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node + { + public: + + typedef T value_type; + typedef T0oT1oT2oT3_sf4ext node_type; + + T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) + {} + + inline typename expression_node::node_type type() const exprtk_override + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; + return result; + } + + inline T value() const exprtk_override + { + 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_; + } + + std::string type_id() const exprtk_override + { + return id(); + } + + static inline std::string id() + { + return SF4Operation::id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) + { + return allocator + .template allocate_type + (p0, p1, p2, p3); + } + + private: + + T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + }; + + template + inline bool is_sf4ext_node(const expression_node* n) + { + switch (n->type()) + { + case expression_node::e_vovovov : return true; + case expression_node::e_vovovoc : return true; + case expression_node::e_vovocov : return true; + case expression_node::e_vocovov : return true; + case expression_node::e_covovov : return true; + case expression_node::e_covocov : return true; + case expression_node::e_vocovoc : return true; + case expression_node::e_covovoc : return true; + case expression_node::e_vococov : return true; + default : return false; + } + } + + template + struct T0oT1_define + { + typedef details::T0oT1 type0; + }; + + template + struct T0oT1oT2_define + { + typedef details::T0oT1oT2::mode0> type0; + typedef details::T0oT1oT2::mode1> type1; + typedef details::T0oT1oT2_sf3 sf3_type; + typedef details::sf3ext_type_node sf3_type_node; + }; + + template + struct T0oT1oT2oT3_define + { + typedef details::T0oT1oT2oT3::mode0> type0; + typedef details::T0oT1oT2oT3::mode1> type1; + typedef details::T0oT1oT2oT3::mode2> type2; + typedef details::T0oT1oT2oT3::mode3> type3; + typedef details::T0oT1oT2oT3::mode4> type4; + typedef details::T0oT1oT2oT3_sf4 sf4_type; + }; + + template + class vov_node exprtk_final : public vov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // variable op variable node + explicit vov_node(const T& var0, const T& var1) + : v0_(var0) + , v1_(var1) + {} + + inline T value() const exprtk_override + { + return Operation::process(v0_,v1_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T& v0() const exprtk_override + { + return v0_; + } + + inline const T& v1() const exprtk_override + { + return v1_; + } + + protected: + + const T& v0_; + const T& v1_; + + private: + + vov_node(const vov_node&) exprtk_delete; + vov_node& operator=(const vov_node&) exprtk_delete; + }; + + template + class cov_node exprtk_final : public cov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // constant op variable node + explicit cov_node(const T& const_var, const T& var) + : c_(const_var) + , v_(var) + {} + + inline T value() const exprtk_override + { + return Operation::process(c_,v_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T c() const exprtk_override + { + return c_; + } + + inline const T& v() const exprtk_override + { + return v_; + } + + protected: + + const T c_; + const T& v_; + + private: + + cov_node(const cov_node&) exprtk_delete; + cov_node& operator=(const cov_node&) exprtk_delete; + }; + + template + class voc_node exprtk_final : public voc_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // variable op constant node + explicit voc_node(const T& var, const T& const_var) + : v_(var) + , c_(const_var) + {} + + inline T value() const exprtk_override + { + return Operation::process(v_,c_); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T c() const exprtk_override + { + return c_; + } + + inline const T& v() const exprtk_override + { + return v_; + } + + protected: + + const T& v_; + const T c_; + + private: + + voc_node(const voc_node&) exprtk_delete; + voc_node& operator=(const voc_node&) exprtk_delete; + }; + + template + class vob_node exprtk_final : public vob_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return Operation::process(v_,branch_.first->value()); + } + + inline const T& v() const exprtk_override + { + return v_; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + vob_node(const vob_node&) exprtk_delete; + vob_node& operator=(const vob_node&) exprtk_delete; + + const T& v_; + branch_t branch_; + }; + + template + class bov_node exprtk_final : public bov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return Operation::process(branch_.first->value(),v_); + } + + inline const T& v() const exprtk_override + { + return v_; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bov_node(const bov_node&) exprtk_delete; + bov_node& operator=(const bov_node&) exprtk_delete; + + const T& v_; + branch_t branch_; + }; + + template + class cob_node exprtk_final : public cob_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return Operation::process(c_,branch_.first->value()); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T c() const exprtk_override + { + return c_; + } + + inline void set_c(const T new_c) exprtk_override + { + (*const_cast(&c_)) = new_c; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + inline expression_node* move_branch(const std::size_t&) exprtk_override + { + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + cob_node(const cob_node&) exprtk_delete; + cob_node& operator=(const cob_node&) exprtk_delete; + + const T c_; + branch_t branch_; + }; + + template + class boc_node exprtk_final : public boc_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair 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); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return Operation::process(branch_.first->value(),c_); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline const T c() const exprtk_override + { + return c_; + } + + inline void set_c(const T new_c) exprtk_override + { + (*const_cast(&c_)) = new_c; + } + + inline expression_node* branch(const std::size_t&) const exprtk_override + { + return branch_.first; + } + + inline expression_node* move_branch(const std::size_t&) exprtk_override + { + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + boc_node(const boc_node&) exprtk_delete; + boc_node& operator=(const boc_node&) exprtk_delete; + + const T c_; + branch_t branch_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class sos_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // string op string node + explicit sos_node(SType0 p0, SType1 p1) + : s0_(p0) + , s1_(p1) + {} + + inline T value() const exprtk_override + { + return Operation::process(s0_,s1_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + + private: + + sos_node(const sos_node&) exprtk_delete; + sos_node& operator=(const sos_node&) exprtk_delete; + }; + + template + class str_xrox_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + typedef str_xrox_node node_type; + + // string-range op string node + explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) + : s0_ (p0 ) + , s1_ (p1 ) + , rp0_(rp0) + {} + + ~str_xrox_node() + { + rp0_.free(); + } + + inline T value() const exprtk_override + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp0_(r0, r1, s0_.size())) + return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); + else + return T(0); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp0_; + + private: + + str_xrox_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + }; + + template + class str_xoxr_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + typedef str_xoxr_node node_type; + + // string op string range node + explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) + : s0_ (p0 ) + , s1_ (p1 ) + , rp1_(rp1) + {} + + ~str_xoxr_node() + { + rp1_.free(); + } + + inline T value() const exprtk_override + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp1_(r0, r1, s1_.size())) + return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); + else + return T(0); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp1_; + + private: + + str_xoxr_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + }; + + template + class str_xroxr_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + typedef str_xroxr_node node_type; + + // string-range op string-range node + explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) + : s0_ (p0 ) + , s1_ (p1 ) + , rp0_(rp0) + , rp1_(rp1) + {} + + ~str_xroxr_node() + { + rp0_.free(); + rp1_.free(); + } + + inline T value() const exprtk_override + { + std::size_t r0_0 = 0; + std::size_t r0_1 = 0; + std::size_t r1_0 = 0; + std::size_t r1_1 = 0; + + if ( + rp0_(r0_0, r1_0, s0_.size()) && + rp1_(r0_1, r1_1, s1_.size()) + ) + { + return Operation::process( + s0_.substr(r0_0, (r1_0 - r0_0) + 1), + s1_.substr(r0_1, (r1_1 - r0_1) + 1) + ); + } + else + return T(0); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp0_; + RangePack rp1_; + + private: + + str_xroxr_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + }; + + template + class str_sogens_node exprtk_final : public binary_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + str_sogens_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + } + + inline T value() const exprtk_override + { + if ( + str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ + ) + { + binary_node::branch_[0].first->value(); + binary_node::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; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + return Operation::process( + str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), + str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) + ); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + private: + + str_sogens_node(const str_sogens_node&) exprtk_delete; + str_sogens_node& operator=(const str_sogens_node&) exprtk_delete; + + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + }; + + template + class sosos_node exprtk_final : public sosos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + typedef sosos_node node_type; + + // variable op variable node + explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) + : s0_(p0) + , s1_(p1) + , s2_(p2) + {} + + inline T value() const exprtk_override + { + return Operation::process(s0_, s1_, s2_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return Operation::type(); + } + + inline operator_type operation() const exprtk_override + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + inline std::string& s2() + { + return s2_; + } + + protected: + + SType0 s0_; + SType1 s1_; + SType2 s2_; + + private: + + sosos_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; + }; + #endif + + template + class ipow_node exprtk_final: public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef PowOp operation_t; + + explicit ipow_node(const T& v) + : v_(v) + {} + + inline T value() const exprtk_override + { + return PowOp::result(v_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_ipow; + } + + private: + + ipow_node(const ipow_node&) exprtk_delete; + ipow_node& operator=(const ipow_node&) exprtk_delete; + + const T& v_; + }; + + template + class bipow_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipow_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return PowOp::result(branch_.first->value()); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_ipow; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bipow_node(const bipow_node&) exprtk_delete; + bipow_node& operator=(const bipow_node&) exprtk_delete; + + branch_t branch_; + }; + + template + class ipowinv_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef PowOp operation_t; + + explicit ipowinv_node(const T& v) + : v_(v) + {} + + inline T value() const exprtk_override + { + return (T(1) / PowOp::result(v_)); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_ipowinv; + } + + private: + + ipowinv_node(const ipowinv_node&) exprtk_delete; + ipowinv_node& operator=(const ipowinv_node&) exprtk_delete; + + const T& v_; + }; + + template + class bipowninv_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipowninv_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const exprtk_override + { + assert(branch_.first); + return (T(1) / PowOp::result(branch_.first->value())); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_ipowinv; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bipowninv_node(const bipowninv_node&) exprtk_delete; + bipowninv_node& operator=(const bipowninv_node&) exprtk_delete; + + branch_t branch_; + }; + + template + inline bool is_vov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_voc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cob_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_boc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2ot3_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_uv_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_string_node(const expression_node* node) + { + return node && (expression_node::e_stringvar == node->type()); + } + + template + inline bool is_string_range_node(const expression_node* node) + { + return node && (expression_node::e_stringvarrng == node->type()); + } + + template + inline bool is_const_string_node(const expression_node* node) + { + return node && (expression_node::e_stringconst == node->type()); + } + + template + inline bool is_const_string_range_node(const expression_node* node) + { + return node && (expression_node::e_cstringvarrng == node->type()); + } + + template + inline bool is_string_assignment_node(const expression_node* node) + { + return node && (expression_node::e_strass == node->type()); + } + + template + inline bool is_string_concat_node(const expression_node* node) + { + return node && (expression_node::e_strconcat == node->type()); + } + + template + inline bool is_string_function_node(const expression_node* node) + { + return node && (expression_node::e_strfunction == node->type()); + } + + template + inline bool is_string_condition_node(const expression_node* node) + { + return node && (expression_node::e_strcondition == node->type()); + } + + template + inline bool is_string_ccondition_node(const expression_node* node) + { + return node && (expression_node::e_strccondition == node->type()); + } + + template + inline bool is_string_vararg_node(const expression_node* node) + { + return node && (expression_node::e_stringvararg == node->type()); + } + + template + inline bool is_genricstring_range_node(const expression_node* node) + { + return node && (expression_node::e_strgenrange == node->type()); + } + + template + inline bool is_generally_string_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case expression_node::e_stringvar : + case expression_node::e_stringconst : + case expression_node::e_stringvarrng : + case expression_node::e_cstringvarrng : + case expression_node::e_strgenrange : + case expression_node::e_strass : + case expression_node::e_strconcat : + case expression_node::e_strfunction : + case expression_node::e_strcondition : + case expression_node::e_strccondition : + case expression_node::e_stringvararg : return true; + default : return false; + } + } + + return false; + } + + class node_allocator + { + public: + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) + { + expression_node* result = + allocate(operation, branch[0]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) + { + expression_node* result = + allocate(operation, branch[0], branch[1]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) + { + expression_node* result = + allocate(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate() const + { + return (new node_type()); + } + + template class Sequence> + inline expression_node* allocate(const Sequence& seq) const + { + expression_node* + result = (new node_type(seq)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(T1& t1) const + { + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_c(const T1& t1) const + { + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_cr(const T1& t1, T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rc(T1& t1, const T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rr(T1& t1, T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_tt(T1 t1, T2 t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8, + const T9& t9) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8, + const T9& t9, const T10& t10) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6, + T7 t7) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; + } + + template + void inline free(expression_node*& e) const + { + exprtk_debug(("node_allocator::free() - deleting expression_node " + "type: %03d addr: %p\n", + static_cast(e->type()), + reinterpret_cast(e))); + delete e; + e = 0; + } + }; + + inline void load_operations_map(std::multimap& m) + { + #define register_op(Symbol, Type, Args) \ + m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ + + register_op("abs" , e_abs , 1) + register_op("acos" , e_acos , 1) + register_op("acosh" , e_acosh , 1) + register_op("asin" , e_asin , 1) + register_op("asinh" , e_asinh , 1) + register_op("atan" , e_atan , 1) + register_op("atanh" , e_atanh , 1) + register_op("ceil" , e_ceil , 1) + register_op("cos" , e_cos , 1) + register_op("cosh" , e_cosh , 1) + register_op("exp" , e_exp , 1) + register_op("expm1" , e_expm1 , 1) + register_op("floor" , e_floor , 1) + register_op("log" , e_log , 1) + register_op("log10" , e_log10 , 1) + register_op("log2" , e_log2 , 1) + register_op("log1p" , e_log1p , 1) + register_op("round" , e_round , 1) + register_op("sin" , e_sin , 1) + register_op("sinc" , e_sinc , 1) + register_op("sinh" , e_sinh , 1) + register_op("sec" , e_sec , 1) + register_op("csc" , e_csc , 1) + register_op("sqrt" , e_sqrt , 1) + register_op("tan" , e_tan , 1) + register_op("tanh" , e_tanh , 1) + register_op("cot" , e_cot , 1) + register_op("rad2deg" , e_r2d , 1) + register_op("deg2rad" , e_d2r , 1) + register_op("deg2grad" , e_d2g , 1) + register_op("grad2deg" , e_g2d , 1) + register_op("sgn" , e_sgn , 1) + register_op("not" , e_notl , 1) + register_op("erf" , e_erf , 1) + register_op("erfc" , e_erfc , 1) + register_op("ncdf" , e_ncdf , 1) + register_op("frac" , e_frac , 1) + register_op("trunc" , e_trunc , 1) + register_op("atan2" , e_atan2 , 2) + register_op("mod" , e_mod , 2) + register_op("logn" , e_logn , 2) + register_op("pow" , e_pow , 2) + register_op("root" , e_root , 2) + register_op("roundn" , e_roundn , 2) + register_op("equal" , e_equal , 2) + register_op("not_equal" , e_nequal , 2) + register_op("hypot" , e_hypot , 2) + register_op("shr" , e_shr , 2) + register_op("shl" , e_shl , 2) + register_op("clamp" , e_clamp , 3) + register_op("iclamp" , e_iclamp , 3) + register_op("inrange" , e_inrange , 3) + #undef register_op + } + + } // namespace details + + class function_traits + { + public: + + function_traits() + : allow_zero_parameters_(false) + , has_side_effects_(true) + , min_num_args_(0) + , max_num_args_(std::numeric_limits::max()) + {} + + inline bool& allow_zero_parameters() + { + return allow_zero_parameters_; + } + + inline bool& has_side_effects() + { + return has_side_effects_; + } + + std::size_t& min_num_args() + { + return min_num_args_; + } + + std::size_t& max_num_args() + { + return max_num_args_; + } + + private: + + bool allow_zero_parameters_; + bool has_side_effects_; + std::size_t min_num_args_; + std::size_t max_num_args_; + }; + + template + void enable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = true; + + if (0 != func.min_num_args()) + { + func.min_num_args() = 0; + } + } + + template + void disable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = false; + } + + template + void enable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = true; + } + + template + void disable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = false; + } + + template + void set_min_num_args(FunctionType& func, const std::size_t& num_args) + { + func.min_num_args() = num_args; + + if ((0 != func.min_num_args()) && func.allow_zero_parameters()) + func.allow_zero_parameters() = false; + } + + template + void set_max_num_args(FunctionType& func, const std::size_t& num_args) + { + func.max_num_args() = num_args; + } + + template + class ifunction : public function_traits + { + public: + + explicit ifunction(const std::size_t& pc) + : param_count(pc) + {} + + virtual ~ifunction() {} + + #define empty_method_body(N) \ + { \ + exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + inline virtual T operator() () + empty_method_body(0) + + inline virtual T operator() (const T&) + empty_method_body(1) + + inline virtual T operator() (const T&,const T&) + empty_method_body(2) + + inline virtual T operator() (const T&, const T&, const T&) + empty_method_body(3) + + inline virtual T operator() (const T&, const T&, const T&, const T&) + empty_method_body(4) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) + empty_method_body(5) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(6) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(7) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(8) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(9) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(10) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&) + empty_method_body(11) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&) + empty_method_body(12) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&) + empty_method_body(13) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&) + empty_method_body(14) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&) + empty_method_body(15) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(16) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(17) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(18) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(19) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(20) + + #undef empty_method_body + + std::size_t param_count; + }; + + template + class ivararg_function : public function_traits + { + public: + + virtual ~ivararg_function() {} + + inline virtual T operator() (const std::vector&) + { + exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); + return std::numeric_limits::quiet_NaN(); + } + }; + + template + class igeneric_function : public function_traits + { + public: + + enum return_type + { + e_rtrn_scalar = 0, + e_rtrn_string = 1, + e_rtrn_overload = 2 + }; + + typedef T type; + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + : parameter_sequence(param_seq) + , rtrn_type(rtr_type) + {} + + virtual ~igeneric_function() {} + + #define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + // f(i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (parameter_list_t) + igeneric_function_empty_body(1) + + // f(i_0,i_1,....,i_N) --> String + inline virtual T operator() (std::string&, parameter_list_t) + igeneric_function_empty_body(2) + + // f(psi,i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (const std::size_t&, parameter_list_t) + igeneric_function_empty_body(3) + + // f(psi,i_0,i_1,....,i_N) --> String + inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) + igeneric_function_empty_body(4) + + std::string parameter_sequence; + return_type rtrn_type; + }; + + #ifndef exprtk_disable_string_capabilities + template + class stringvar_base + { + public: + + typedef typename details::stringvar_node stringvar_node_t; + + stringvar_base(const std::string& name, stringvar_node_t* svn) + : name_(name) + , string_varnode_(svn) + {} + + bool valid() const + { + return !name_.empty() && (0 != string_varnode_); + } + + std::string name() const + { + assert(string_varnode_); + return name_; + } + + void rebase(std::string& s) + { + assert(string_varnode_); + string_varnode_->rebase(s); + } + + private: + + std::string name_; + stringvar_node_t* string_varnode_; + }; + #endif + + template class parser; + template class expression_helper; + + template + class symbol_table + { + public: + + typedef T (*ff00_functor)(); + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); + + protected: + + struct freefunc00 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} + inline T operator() () + { return f(); } + ff00_functor f; + }; + + struct freefunc01 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} + inline T operator() (const T& v0) + { return f(v0); } + ff01_functor f; + }; + + struct freefunc02 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} + inline T operator() (const T& v0, const T& v1) + { return f(v0, v1); } + ff02_functor f; + }; + + struct freefunc03 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2) + { return f(v0, v1, v2); } + ff03_functor f; + }; + + struct freefunc04 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) + { return f(v0, v1, v2, v3); } + ff04_functor f; + }; + + struct freefunc05 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { return f(v0, v1, v2, v3, v4); } + ff05_functor f; + }; + + struct freefunc06 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { return f(v0, v1, v2, v3, v4, v5); } + ff06_functor f; + }; + + struct freefunc07 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { return f(v0, v1, v2, v3, v4, v5, v6); } + ff07_functor f; + }; + + struct freefunc08 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { return f(v0, v1, v2, v3, v4, v5, v6, v7); } + ff08_functor f; + }; + + struct freefunc09 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } + ff09_functor f; + }; + + struct freefunc10 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } + ff10_functor f; + }; + + struct freefunc11 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } + ff11_functor f; + }; + + struct freefunc12 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } + ff12_functor f; + }; + + struct freefunc13 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } + ff13_functor f; + }; + + struct freefunc14 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } + ff14_functor f; + }; + + struct freefunc15 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } + ff15_functor f; + }; + + template + struct type_store + { + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_node_t; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::vector_holder vector_t; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_node_t; + #endif + + typedef Type type_t; + typedef type_t* type_ptr; + typedef std::pair type_pair_t; + typedef std::map type_map_t; + typedef typename type_map_t::iterator tm_itr_t; + typedef typename type_map_t::const_iterator tm_const_itr_t; + + enum { lut_size = 256 }; + + type_map_t map; + std::size_t size; + + type_store() + : size(0) + {} + + struct deleter + { + #define exprtk_define_process(Type) \ + static inline void process(std::pair& n) \ + { \ + delete n.second; \ + } \ + + exprtk_define_process(variable_node_t ) + exprtk_define_process(vector_t ) + #ifndef exprtk_disable_string_capabilities + exprtk_define_process(stringvar_node_t) + #endif + + #undef exprtk_define_process + + template + static inline void process(std::pair&) + {} + }; + + inline bool symbol_exists(const std::string& symbol_name) const + { + if (symbol_name.empty()) + return false; + else if (map.end() != map.find(symbol_name)) + return true; + else + return false; + } + + template + inline std::string entity_name(const PtrType& ptr) const + { + if (map.empty()) + return std::string(); + + tm_const_itr_t itr = map.begin(); + + while (map.end() != itr) + { + if (itr->second.second == ptr) + { + return itr->first; + } + else + ++itr; + } + + return std::string(); + } + + inline bool is_constant(const std::string& symbol_name) const + { + if (symbol_name.empty()) + return false; + else + { + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return false; + else + return (*itr).second.first; + } + } + + template + inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) + { + if (symbol_name.size() > 1) + { + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + if (details::imatch(symbol_name, details::reserved_symbols[i])) + { + return false; + } + } + } + + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + { + map[symbol_name] = Tie::make(t,is_const); + ++size; + } + + return true; + } + + struct tie_array + { + static inline std::pair make(std::pair v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v.first, v.second)); + } + }; + + struct tie_stdvec + { + template + static inline std::pair make(std::vector& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + struct tie_vecview + { + static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + struct tie_stddeq + { + template + static inline std::pair make(std::deque& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + template + inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) + { + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); + } + + inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) + { + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); + } + + template + inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + template + inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + inline bool add(const std::string& symbol_name, RawType& t_, const bool is_const = false) + { + struct tie + { + static inline std::pair make(T& t, const bool is_constant = false) + { + return std::make_pair(is_constant, new variable_node_t(t)); + } + + #ifndef exprtk_disable_string_capabilities + static inline std::pair make(std::string& t, const bool is_constant = false) + { + return std::make_pair(is_constant, new stringvar_node_t(t)); + } + #endif + + static inline std::pair make(function_t& t, const bool is_constant = false) + { + return std::make_pair(is_constant,&t); + } + + static inline std::pair make(vararg_function_t& t, const bool is_constant = false) + { + return std::make_pair(is_constant,&t); + } + + static inline std::pair make(generic_function_t& t, const bool is_constant = false) + { + return std::make_pair(is_constant,&t); + } + }; + + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + { + map[symbol_name] = tie::make(t_,is_const); + ++size; + } + + return true; + } + + inline type_ptr get(const std::string& symbol_name) const + { + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return reinterpret_cast(0); + else + return itr->second.second; + } + + template + struct ptr_match + { + static inline bool test(const PtrType, const void*) + { + return false; + } + }; + + template + struct ptr_match + { + static inline bool test(const variable_node_t* p, const void* ptr) + { + exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); + return (&(p->ref()) == ptr); + } + }; + + inline type_ptr get_from_varptr(const void* ptr) const + { + tm_const_itr_t itr = map.begin(); + + while (map.end() != itr) + { + type_ptr ret_ptr = itr->second.second; + + if (ptr_match::test(ret_ptr,ptr)) + { + return ret_ptr; + } + + ++itr; + } + + return type_ptr(0); + } + + inline bool remove(const std::string& symbol_name, const bool delete_node = true) + { + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() != itr) + { + if (delete_node) + { + deleter::process((*itr).second); + } + + map.erase(itr); + --size; + + return true; + } + else + return false; + } + + inline RawType& type_ref(const std::string& symbol_name) + { + struct init_type + { + static inline double set(double) { return (0.0); } + static inline double set(long double) { return (0.0); } + static inline float set(float) { return (0.0f); } + static inline std::string set(std::string) { return std::string(""); } + }; + + static RawType null_type = init_type::set(RawType()); + + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return null_type; + else + return itr->second.second->ref(); + } + + inline void clear(const bool delete_node = true) + { + if (!map.empty()) + { + if (delete_node) + { + tm_itr_t itr = map.begin(); + tm_itr_t end = map.end (); + + while (end != itr) + { + deleter::process((*itr).second); + ++itr; + } + } + + map.clear(); + } + + size = 0; + } + + template class Sequence> + inline std::size_t get_list(Sequence,Allocator>& list) const + { + std::size_t count = 0; + + if (!map.empty()) + { + tm_const_itr_t itr = map.begin(); + tm_const_itr_t end = map.end (); + + while (end != itr) + { + list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); + ++itr; + ++count; + } + } + + return count; + } + + template class Sequence> + inline std::size_t get_list(Sequence& vlist) const + { + std::size_t count = 0; + + if (!map.empty()) + { + tm_const_itr_t itr = map.begin(); + tm_const_itr_t end = map.end (); + + while (end != itr) + { + vlist.push_back((*itr).first); + ++itr; + ++count; + } + } + + return count; + } + }; + + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_t; + typedef typename details::vector_holder vector_holder_t; + typedef variable_t* variable_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_t; + typedef stringvar_t* stringvar_ptr; + #endif + typedef ifunction function_t; + typedef ivararg_function vararg_function_t; + typedef igeneric_function generic_function_t; + typedef function_t* function_ptr; + typedef vararg_function_t* vararg_function_ptr; + typedef generic_function_t* generic_function_ptr; + + static const std::size_t lut_size = 256; + + // Symbol Table Holder + struct control_block + { + struct st_data + { + type_store variable_store; + type_store function_store; + type_store vararg_function_store; + type_store generic_function_store; + type_store string_function_store; + type_store overload_function_store; + type_store vector_store; + #ifndef exprtk_disable_string_capabilities + type_store stringvar_store; + #endif + + st_data() + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_words[i]); + } + + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_symbols[i]); + } + } + + ~st_data() + { + for (std::size_t i = 0; i < free_function_list_.size(); ++i) + { + delete free_function_list_[i]; + } + } + + inline bool is_reserved_symbol(const std::string& symbol) const + { + return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); + } + + static inline st_data* create() + { + return (new st_data); + } + + static inline void destroy(st_data*& sd) + { + delete sd; + sd = reinterpret_cast(0); + } + + std::list local_symbol_list_; + std::list local_stringvar_list_; + std::set reserved_symbol_table_; + std::vector*> free_function_list_; + }; + + control_block() + : ref_count(1) + , data_(st_data::create()) + {} + + explicit control_block(st_data* data) + : ref_count(1) + , data_(data) + {} + + ~control_block() + { + if (data_ && (0 == ref_count)) + { + st_data::destroy(data_); + } + } + + static inline control_block* create() + { + return (new control_block); + } + + template + static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + if (sym_tab) + sym_tab->clear(); + + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + st_data* data_; + }; + + public: + + symbol_table() + : control_block_(control_block::create()) + { + clear(); + } + + ~symbol_table() + { + control_block::destroy(control_block_,this); + } + + symbol_table(const symbol_table& st) + { + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + inline symbol_table& operator=(const symbol_table& st) + { + if (this != &st) + { + control_block::destroy(control_block_,reinterpret_cast*>(0)); + + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + return (*this); + } + + inline bool operator==(const symbol_table& st) const + { + return (this == &st) || (control_block_ == st.control_block_); + } + + inline void clear_variables(const bool delete_node = true) + { + local_data().variable_store.clear(delete_node); + } + + inline void clear_functions() + { + local_data().function_store.clear(); + } + + inline void clear_strings() + { + #ifndef exprtk_disable_string_capabilities + local_data().stringvar_store.clear(); + #endif + } + + inline void clear_vectors() + { + local_data().vector_store.clear(); + } + + inline void clear_local_constants() + { + local_data().local_symbol_list_.clear(); + } + + inline void clear() + { + if (!valid()) return; + clear_variables (); + clear_functions (); + clear_strings (); + clear_vectors (); + clear_local_constants(); + } + + inline std::size_t variable_count() const + { + if (valid()) + return local_data().variable_store.size; + else + return 0; + } + + #ifndef exprtk_disable_string_capabilities + inline std::size_t stringvar_count() const + { + if (valid()) + return local_data().stringvar_store.size; + else + return 0; + } + #endif + + inline std::size_t function_count() const + { + if (valid()) + return local_data().function_store.size; + else + return 0; + } + + inline std::size_t vector_count() const + { + if (valid()) + return local_data().vector_store.size; + else + return 0; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + else + return local_data().variable_store.get(variable_name); + } + + inline variable_ptr get_variable(const T& var_ref) const + { + if (!valid()) + return reinterpret_cast(0); + else + return local_data().variable_store.get_from_varptr( + reinterpret_cast(&var_ref)); + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(string_name)) + return reinterpret_cast(0); + else + return local_data().stringvar_store.get(string_name); + } + + inline stringvar_base get_stringvar_base(const std::string& string_name) const + { + static stringvar_base null_stringvar_base("",reinterpret_cast(0)); + if (!valid()) + return null_stringvar_base; + else if (!valid_symbol(string_name)) + return null_stringvar_base; + + stringvar_ptr stringvar = local_data().stringvar_store.get(string_name); + + if (0 == stringvar) + { + return null_stringvar_base; + } + + return stringvar_base(string_name,stringvar); + } + #endif + + inline function_ptr get_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().function_store.get(function_name); + } + + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(vararg_function_name)) + return reinterpret_cast(0); + else + return local_data().vararg_function_store.get(vararg_function_name); + } + + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().generic_function_store.get(function_name); + } + + inline generic_function_ptr get_string_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().string_function_store.get(function_name); + } + + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().overload_function_store.get(function_name); + } + + typedef vector_holder_t* vector_holder_ptr; + + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(vector_name)) + return reinterpret_cast(0); + else + return local_data().vector_store.get(vector_name); + } + + inline T& variable_ref(const std::string& symbol_name) + { + static T null_var = T(0); + if (!valid()) + return null_var; + else if (!valid_symbol(symbol_name)) + return null_var; + else + return local_data().variable_store.type_ref(symbol_name); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string& stringvar_ref(const std::string& symbol_name) + { + static std::string null_stringvar; + if (!valid()) + return null_stringvar; + else if (!valid_symbol(symbol_name)) + return null_stringvar; + else + return local_data().stringvar_store.type_ref(symbol_name); + } + #endif + + inline bool is_constant_node(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else + return local_data().variable_store.is_constant(symbol_name); + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else if (!local_data().stringvar_store.symbol_exists(symbol_name)) + return false; + else + return local_data().stringvar_store.is_constant(symbol_name); + } + #endif + + inline bool create_variable(const std::string& variable_name, const T& value = T(0)) + { + if (!valid()) + return false; + else if (!valid_symbol(variable_name)) + return false; + else if (symbol_exists(variable_name)) + return false; + + local_data().local_symbol_list_.push_back(value); + T& t = local_data().local_symbol_list_.back(); + + return add_variable(variable_name,t); + } + + #ifndef exprtk_disable_string_capabilities + inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) + { + if (!valid()) + return false; + else if (!valid_symbol(stringvar_name)) + return false; + else if (symbol_exists(stringvar_name)) + return false; + + local_data().local_stringvar_list_.push_back(value); + std::string& s = local_data().local_stringvar_list_.back(); + + return add_stringvar(stringvar_name,s); + } + #endif + + inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) + { + if (!valid()) + return false; + else if (!valid_symbol(variable_name)) + return false; + else if (symbol_exists(variable_name)) + return false; + else + return local_data().variable_store.add(variable_name, t, is_constant); + } + + inline bool add_constant(const std::string& constant_name, const T& value) + { + if (!valid()) + return false; + else if (!valid_symbol(constant_name)) + return false; + else if (symbol_exists(constant_name)) + return false; + + local_data().local_symbol_list_.push_back(value); + T& t = local_data().local_symbol_list_.back(); + + return add_variable(constant_name, t, true); + } + + #ifndef exprtk_disable_string_capabilities + inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) + { + if (!valid()) + return false; + else if (!valid_symbol(stringvar_name)) + return false; + else if (symbol_exists(stringvar_name)) + return false; + else + return local_data().stringvar_store.add(stringvar_name, s, is_constant); + } + #endif + + inline bool add_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name)) + return false; + else if (symbol_exists(vararg_function_name)) + return false; + else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; + } + + #define exprtk_define_freefunction(NN) \ + inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name)) \ + { return false; } \ + if (symbol_exists(function_name)) \ + { return false; } \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_freefunction(00) exprtk_define_freefunction(01) + exprtk_define_freefunction(02) exprtk_define_freefunction(03) + exprtk_define_freefunction(04) exprtk_define_freefunction(05) + exprtk_define_freefunction(06) exprtk_define_freefunction(07) + exprtk_define_freefunction(08) exprtk_define_freefunction(09) + exprtk_define_freefunction(10) exprtk_define_freefunction(11) + exprtk_define_freefunction(12) exprtk_define_freefunction(13) + exprtk_define_freefunction(14) exprtk_define_freefunction(15) + + #undef exprtk_define_freefunction + + inline bool add_reserved_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name,false)) + return false; + else if (symbol_exists(vararg_function_name,false)) + return false; + else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; + } + + template + inline bool add_vector(const std::string& vector_name, T (&v)[N]) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v_size) + return false; + else + return local_data().vector_store.add(vector_name, v, v_size); + } + + template + inline bool add_vector(const std::string& vector_name, std::vector& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v.size()) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v.size()) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) + { + if (!valid()) + return false; + else + return local_data().variable_store.remove(variable_name, delete_node); + } + + #ifndef exprtk_disable_string_capabilities + inline bool remove_stringvar(const std::string& string_name) + { + if (!valid()) + return false; + else + return local_data().stringvar_store.remove(string_name); + } + #endif + + inline bool remove_function(const std::string& function_name) + { + if (!valid()) + return false; + else + return local_data().function_store.remove(function_name); + } + + inline bool remove_vararg_function(const std::string& vararg_function_name) + { + if (!valid()) + return false; + else + return local_data().vararg_function_store.remove(vararg_function_name); + } + + inline bool remove_vector(const std::string& vector_name) + { + if (!valid()) + return false; + else + return local_data().vector_store.remove(vector_name); + } + + inline bool add_constants() + { + return add_pi () && + add_epsilon () && + add_infinity() ; + } + + inline bool add_pi() + { + const typename details::numeric::details::number_type::type num_type; + static const T local_pi = details::numeric::details::const_pi_impl(num_type); + return add_constant("pi",local_pi); + } + + inline bool add_epsilon() + { + static const T local_epsilon = details::numeric::details::epsilon_type::value(); + return add_constant("epsilon",local_epsilon); + } + + inline bool add_infinity() + { + static const T local_infinity = std::numeric_limits::infinity(); + return add_constant("inf",local_infinity); + } + + template + inline bool add_package(Package& package) + { + return package.register_package(*this); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + #ifndef exprtk_disable_string_capabilities + template class Sequence> + inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + + template class Sequence> + inline std::size_t get_stringvar_list(Sequence& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + #endif + + template class Sequence> + inline std::size_t get_vector_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().vector_store.get_list(vlist); + } + + inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const + { + /* + Function will return true if symbol_name exists as either a + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. + */ + if (!valid()) + return false; + else if (local_data().variable_store.symbol_exists(symbol_name)) + return true; + #ifndef exprtk_disable_string_capabilities + else if (local_data().stringvar_store.symbol_exists(symbol_name)) + return true; + #endif + else if (local_data().vector_store.symbol_exists(symbol_name)) + return true; + else if (local_data().function_store.symbol_exists(symbol_name)) + return true; + else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) + return true; + else + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + if (!valid()) + return false; + else + return local_data().variable_store.symbol_exists(variable_name); + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + if (!valid()) + return false; + else + return local_data().stringvar_store.symbol_exists(stringvar_name); + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else if (!local_data().stringvar_store.symbol_exists(symbol_name)) + return false; + + return ( + local_data().stringvar_store.symbol_exists(symbol_name) || + local_data().stringvar_store.is_constant (symbol_name) + ); + } + #endif + + inline bool is_function(const std::string& function_name) const + { + if (!valid()) + return false; + else + return local_data().function_store.symbol_exists(function_name); + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + if (!valid()) + return false; + else + return local_data().vararg_function_store.symbol_exists(vararg_function_name); + } + + inline bool is_vector(const std::string& vector_name) const + { + if (!valid()) + return false; + else + return local_data().vector_store.symbol_exists(vector_name); + } + + inline std::string get_variable_name(const expression_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline bool valid() const + { + // Symbol table sanity check. + return control_block_ && control_block_->data_; + } + + inline void load_from(const symbol_table& st) + { + { + std::vector name_list; + + st.local_data().function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::ifunction& ifunc = *st.get_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().vararg_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); + add_function(name_list[i],ivafunc); + } + } + } + + { + std::vector name_list; + + st.local_data().generic_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_generic_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().string_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().overload_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_overload_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + } + + private: + + inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; + } + } + } + + return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; + } + + inline bool valid_function(const std::string& symbol) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; + } + } + } + + return true; + } + + typedef typename control_block::st_data local_data_t; + + inline local_data_t& local_data() + { + return *(control_block_->data_); + } + + inline const local_data_t& local_data() const + { + return *(control_block_->data_); + } + + control_block* control_block_; + + friend class parser; + }; // class symbol_table + + template + class function_compositor; + + template + class expression + { + private: + + typedef details::expression_node* expression_ptr; + typedef details::vector_holder* vector_holder_ptr; + typedef std::vector > symtab_list_t; + + struct control_block + { + enum data_type + { + e_unknown , + e_expr , + e_vecholder, + e_data , + e_vecdata , + e_string + }; + + struct data_pack + { + data_pack() + : pointer(0) + , type(e_unknown) + , size(0) + {} + + data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) + : pointer(ptr) + , type(dt) + , size(sz) + {} + + void* pointer; + data_type type; + std::size_t size; + }; + + typedef std::vector local_data_list_t; + typedef results_context results_context_t; + typedef control_block* cntrl_blck_ptr_t; + + control_block() + : ref_count(0) + , expr (0) + , results (0) + , retinv_null(false) + , return_invoked(&retinv_null) + {} + + explicit control_block(expression_ptr e) + : ref_count(1) + , expr (e) + , results (0) + , retinv_null(false) + , return_invoked(&retinv_null) + {} + + ~control_block() + { + if (expr && details::branch_deletable(expr)) + { + destroy_node(expr); + } + + if (!local_data_list.empty()) + { + for (std::size_t i = 0; i < local_data_list.size(); ++i) + { + switch (local_data_list[i].type) + { + case e_expr : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_data : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); + break; + + case e_string : delete reinterpret_cast(local_data_list[i].pointer); + break; + + default : break; + } + } + } + + if (results) + { + delete results; + } + } + + static inline cntrl_blck_ptr_t create(expression_ptr e) + { + return new control_block(e); + } + + static inline void destroy(cntrl_blck_ptr_t& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + expression_ptr expr; + local_data_list_t local_data_list; + results_context_t* results; + bool retinv_null; + bool* return_invoked; + + friend class function_compositor; + }; + + public: + + expression() + : control_block_(0) + { + set_expression(new details::null_node()); + } + + expression(const expression& e) + : control_block_ (e.control_block_ ) + , symbol_table_list_(e.symbol_table_list_) + { + control_block_->ref_count++; + } + + explicit expression(const symbol_table& symbol_table) + : control_block_(0) + { + set_expression(new details::null_node()); + symbol_table_list_.push_back(symbol_table); + } + + inline expression& operator=(const expression& e) + { + if (this != &e) + { + if (control_block_) + { + if ( + (0 != control_block_->ref_count) && + (0 == --control_block_->ref_count) + ) + { + delete control_block_; + } + + control_block_ = 0; + } + + control_block_ = e.control_block_; + control_block_->ref_count++; + symbol_table_list_ = e.symbol_table_list_; + } + + return *this; + } + + inline bool operator==(const expression& e) const + { + return (this == &e); + } + + inline bool operator!() const + { + return ( + (0 == control_block_ ) || + (0 == control_block_->expr) + ); + } + + inline expression& release() + { + control_block::destroy(control_block_); + + return (*this); + } + + ~expression() + { + control_block::destroy(control_block_); + } + + inline T value() const + { + assert(control_block_ ); + assert(control_block_->expr); + + return control_block_->expr->value(); + } + + inline T operator() () const + { + return value(); + } + + inline operator T() const + { + return value(); + } + + inline operator bool() const + { + return details::is_true(value()); + } + + inline void register_symbol_table(symbol_table& st) + { + symbol_table_list_.push_back(st); + } + + inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const + { + return symbol_table_list_[index]; + } + + inline symbol_table& get_symbol_table(const std::size_t& index = 0) + { + return symbol_table_list_[index]; + } + + typedef results_context results_context_t; + + inline const results_context_t& results() const + { + if (control_block_->results) + return (*control_block_->results); + else + { + static const results_context_t null_results; + return null_results; + } + } + + inline bool return_invoked() const + { + return (*control_block_->return_invoked); + } + + private: + + inline symtab_list_t get_symbol_table_list() const + { + return symbol_table_list_; + } + + inline void set_expression(const expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + if (0 == --control_block_->ref_count) + { + delete control_block_; + } + } + + control_block_ = control_block::create(expr); + } + } + + inline void register_local_var(expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(expr), + control_block::e_expr)); + } + } + } + + inline void register_local_var(vector_holder_ptr vec_holder) + { + if (vec_holder) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(vec_holder), + control_block::e_vecholder)); + } + } + } + + inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) + { + if (data) + { + if (control_block_) + { + typename control_block::data_type dt = control_block::e_data; + + switch (data_mode) + { + case 0 : dt = control_block::e_data; break; + case 1 : dt = control_block::e_vecdata; break; + case 2 : dt = control_block::e_string; break; + } + + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(data), dt, size)); + } + } + } + + inline const typename control_block::local_data_list_t& local_data_list() + { + if (control_block_) + { + return control_block_->local_data_list; + } + else + { + static typename control_block::local_data_list_t null_local_data_list; + return null_local_data_list; + } + } + + inline void register_return_results(results_context_t* rc) + { + if (control_block_ && rc) + { + control_block_->results = rc; + } + } + + inline void set_retinvk(bool* retinvk_ptr) + { + if (control_block_) + { + control_block_->return_invoked = retinvk_ptr; + } + } + + control_block* control_block_; + symtab_list_t symbol_table_list_; + + friend class parser; + friend class expression_helper; + friend class function_compositor; + }; // class expression + + template + class expression_helper + { + public: + + static inline bool is_constant(const expression& expr) + { + return details::is_constant_node(expr.control_block_->expr); + } + + static inline bool is_variable(const expression& expr) + { + return details::is_variable_node(expr.control_block_->expr); + } + + static inline bool is_unary(const expression& expr) + { + return details::is_unary_node(expr.control_block_->expr); + } + + static inline bool is_binary(const expression& expr) + { + return details::is_binary_node(expr.control_block_->expr); + } + + static inline bool is_function(const expression& expr) + { + return details::is_function(expr.control_block_->expr); + } + + static inline bool is_null(const expression& expr) + { + return details::is_null_node(expr.control_block_->expr); + } + }; + + template + inline bool is_valid(const expression& expr) + { + return !expression_helper::is_null(expr); + } + + namespace parser_error + { + enum error_mode + { + e_unknown = 0, + e_syntax = 1, + e_token = 2, + e_numeric = 4, + e_symtab = 5, + e_lexer = 6, + e_helper = 7, + e_parser = 8 + }; + + struct type + { + type() + : mode(parser_error::e_unknown) + , line_no (0) + , column_no(0) + {} + + lexer::token token; + error_mode mode; + std::string diagnostic; + std::string src_location; + std::string error_line; + std::size_t line_no; + std::size_t column_no; + }; + + inline type make_error(const error_mode mode, + const std::string& diagnostic = "", + const std::string& src_location = "") + { + type t; + t.mode = mode; + t.token.type = lexer::token::e_error; + t.diagnostic = diagnostic; + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); + return t; + } + + inline type make_error(const error_mode mode, + const lexer::token& tk, + const std::string& diagnostic = "", + const std::string& src_location = "") + { + type t; + t.mode = mode; + t.token = tk; + t.diagnostic = diagnostic; + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); + return t; + } + + inline std::string to_str(error_mode mode) + { + switch (mode) + { + case e_unknown : return std::string("Unknown Error"); + case e_syntax : return std::string("Syntax Error" ); + case e_token : return std::string("Token Error" ); + case e_numeric : return std::string("Numeric Error"); + case e_symtab : return std::string("Symbol Error" ); + case e_lexer : return std::string("Lexer Error" ); + case e_helper : return std::string("Helper Error" ); + case e_parser : return std::string("Parser Error" ); + default : return std::string("Unknown Error"); + } + } + + inline bool update_error(type& error, const std::string& expression) + { + if ( + expression.empty() || + (error.token.position > expression.size()) || + (std::numeric_limits::max() == error.token.position) + ) + { + return false; + } + + std::size_t error_line_start = 0; + + for (std::size_t i = error.token.position; i > 0; --i) + { + const details::char_t c = expression[i]; + + if (('\n' == c) || ('\r' == c)) + { + error_line_start = i + 1; + break; + } + } + + std::size_t next_nl_position = std::min(expression.size(), + expression.find_first_of('\n',error.token.position + 1)); + + error.column_no = error.token.position - error_line_start; + error.error_line = expression.substr(error_line_start, + next_nl_position - error_line_start); + + error.line_no = 0; + + for (std::size_t i = 0; i < next_nl_position; ++i) + { + if ('\n' == expression[i]) + ++error.line_no; + } + + return true; + } + + inline void dump_error(const type& error) + { + printf("Position: %02d Type: [%s] Msg: %s\n", + static_cast(error.token.position), + exprtk::parser_error::to_str(error.mode).c_str(), + error.diagnostic.c_str()); + } + } + + namespace details + { + template + inline void disable_type_checking(Parser& p) + { + p.state_.type_check_enabled = false; + } + } + + template + class parser : public lexer::parser_helper + { + private: + + enum precedence_level + { + e_level00, e_level01, e_level02, e_level03, e_level04, + e_level05, e_level06, e_level07, e_level08, e_level09, + e_level10, e_level11, e_level12, e_level13, e_level14 + }; + + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction F; + typedef ivararg_function VAF; + typedef igeneric_function GF; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::cons_conditional_node cons_conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::repeat_until_loop_node repeat_until_loop_node_t; + typedef details::for_loop_node for_loop_node_t; + typedef details::while_loop_rtc_node while_loop_rtc_node_t; + typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; + typedef details::for_loop_rtc_node for_loop_rtc_node_t; + #ifndef exprtk_disable_break_continue + typedef details::while_loop_bc_node while_loop_bc_node_t; + typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; + typedef details::for_loop_bc_node for_loop_bc_node_t; + typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; + typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; + typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; + #endif + typedef details::switch_node switch_node_t; + typedef details::variable_node variable_node_t; + typedef details::vector_elem_node vector_elem_node_t; + typedef details::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; + typedef details::vector_node vector_node_t; + typedef details::range_pack range_t; + #ifndef exprtk_disable_string_capabilities + typedef details::stringvar_node stringvar_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::string_range_node string_range_node_t; + typedef details::const_string_range_node const_string_range_node_t; + typedef details::generic_string_range_node generic_string_range_node_t; + typedef details::string_concat_node string_concat_node_t; + typedef details::assignment_string_node assignment_string_node_t; + typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; + #endif + typedef details::assignment_node assignment_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node assignment_vec_node_t; + typedef details::assignment_vecvec_node assignment_vecvec_node_t; + typedef details::conditional_vector_node conditional_vector_node_t; + typedef details::scand_node scand_node_t; + typedef details::scor_node scor_node_t; + typedef lexer::token token_t; + typedef expression_node_t* expression_node_ptr; + typedef expression expression_t; + typedef symbol_table symbol_table_t; + typedef typename expression::symtab_list_t symbol_table_list_t; + typedef details::vector_holder* vector_holder_ptr; + + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + + typedef details::operator_type operator_t; + + typedef std::map unary_op_map_t; + typedef std::map binary_op_map_t; + typedef std::map trinary_op_map_t; + + typedef std::map > sf3_map_t; + typedef std::map > sf4_map_t; + + typedef std::map inv_binary_op_map_t; + typedef std::multimap base_ops_map_t; + typedef std::set disabled_func_set_t; + + typedef details::T0oT1_define vov_t; + typedef details::T0oT1_define cov_t; + typedef details::T0oT1_define voc_t; + + typedef details::T0oT1oT2_define vovov_t; + typedef details::T0oT1oT2_define vovoc_t; + typedef details::T0oT1oT2_define vocov_t; + typedef details::T0oT1oT2_define covov_t; + typedef details::T0oT1oT2_define covoc_t; + typedef details::T0oT1oT2_define cocov_t; + typedef details::T0oT1oT2_define vococ_t; + + typedef details::T0oT1oT2oT3_define vovovov_t; + typedef details::T0oT1oT2oT3_define vovovoc_t; + typedef details::T0oT1oT2oT3_define vovocov_t; + typedef details::T0oT1oT2oT3_define vocovov_t; + typedef details::T0oT1oT2oT3_define covovov_t; + + typedef details::T0oT1oT2oT3_define covocov_t; + typedef details::T0oT1oT2oT3_define vocovoc_t; + typedef details::T0oT1oT2oT3_define covovoc_t; + typedef details::T0oT1oT2oT3_define vococov_t; + + typedef results_context results_context_t; + + typedef parser_helper prsrhlpr_t; + + struct scope_element + { + enum element_type + { + e_none , + e_variable, + e_vector , + e_vecelem , + e_string + }; + + typedef details::vector_holder vector_holder_t; + typedef variable_node_t* variable_node_ptr; + typedef vector_holder_t* vector_holder_ptr; + typedef expression_node_t* expression_node_ptr; + #ifndef exprtk_disable_string_capabilities + typedef stringvar_node_t* stringvar_node_ptr; + #endif + + scope_element() + : name("???") + , size (std::numeric_limits::max()) + , index(std::numeric_limits::max()) + , depth(std::numeric_limits::max()) + , ref_count(0) + , ip_index (0) + , type (e_none) + , active(false) + , data (0) + , var_node (0) + , vec_node (0) + #ifndef exprtk_disable_string_capabilities + , str_node(0) + #endif + {} + + bool operator < (const scope_element& se) const + { + if (ip_index < se.ip_index) + return true; + else if (ip_index > se.ip_index) + return false; + else if (depth < se.depth) + return true; + else if (depth > se.depth) + return false; + else if (index < se.index) + return true; + else if (index > se.index) + return false; + else + return (name < se.name); + } + + void clear() + { + name = "???"; + size = std::numeric_limits::max(); + index = std::numeric_limits::max(); + depth = std::numeric_limits::max(); + type = e_none; + active = false; + ref_count = 0; + ip_index = 0; + data = 0; + var_node = 0; + vec_node = 0; + #ifndef exprtk_disable_string_capabilities + str_node = 0; + #endif + } + + std::string name; + std::size_t size; + std::size_t index; + std::size_t depth; + std::size_t ref_count; + std::size_t ip_index; + element_type type; + bool active; + void* data; + expression_node_ptr var_node; + vector_holder_ptr vec_node; + #ifndef exprtk_disable_string_capabilities + stringvar_node_ptr str_node; + #endif + }; + + class scope_element_manager + { + public: + + typedef expression_node_t* expression_node_ptr; + typedef variable_node_t* variable_node_ptr; + typedef parser parser_t; + + explicit scope_element_manager(parser& p) + : parser_(p) + , input_param_cnt_(0) + {} + + inline std::size_t size() const + { + return element_.size(); + } + + inline bool empty() const + { + return element_.empty(); + } + + inline scope_element& get_element(const std::size_t& index) + { + if (index < element_.size()) + return element_[index]; + else + return null_element_; + } + + inline scope_element& get_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + details::imatch(se.name, var_name) && + (se.index == index) + ) + return se; + } + + return null_element_; + } + + inline scope_element& get_active_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + details::imatch(se.name, var_name) && + (se.index == index) && + (se.active) + ) + return se; + } + + return null_element_; + } + + inline bool add_element(const scope_element& se) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& cse = element_[i]; + + if ( + details::imatch(cse.name, se.name) && + (cse.depth <= se.depth) && + (cse.index == se.index) && + (cse.size == se.size ) && + (cse.type == se.type ) && + (cse.active) + ) + return false; + } + + element_.push_back(se); + std::sort(element_.begin(),element_.end()); + + return true; + } + + inline void deactivate(const std::size_t& scope_depth) + { + exprtk_debug(("deactivate() - Scope depth: %d\n", + static_cast(parser_.state_.scope_depth))); + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.active && (se.depth >= scope_depth)) + { + exprtk_debug(("deactivate() - element[%02d] '%s'\n", + static_cast(i), + se.name.c_str())); + + se.active = false; + } + } + } + + inline void free_element(scope_element& se) + { + exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + + switch (se.type) + { + case scope_element::e_variable : delete reinterpret_cast(se.data); + delete se.var_node; + break; + + case scope_element::e_vector : delete[] reinterpret_cast(se.data); + delete se.vec_node; + break; + + case scope_element::e_vecelem : delete se.var_node; + break; + + #ifndef exprtk_disable_string_capabilities + case scope_element::e_string : delete reinterpret_cast(se.data); + delete se.str_node; + break; + #endif + + default : return; + } + + se.clear(); + } + + inline void cleanup() + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + free_element(element_[i]); + } + + element_.clear(); + + input_param_cnt_ = 0; + } + + inline std::size_t next_ip_index() + { + return ++input_param_cnt_; + } + + inline expression_node_ptr get_variable(const T& v) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if ( + se.active && + se.var_node && + details::is_variable_node(se.var_node) + ) + { + variable_node_ptr vn = reinterpret_cast(se.var_node); + + if (&(vn->ref()) == (&v)) + { + return se.var_node; + } + } + } + + return expression_node_ptr(0); + } + + private: + + scope_element_manager(const scope_element_manager&) exprtk_delete; + scope_element_manager& operator=(const scope_element_manager&) exprtk_delete; + + parser_t& parser_; + std::vector element_; + scope_element null_element_; + std::size_t input_param_cnt_; + }; + + class scope_handler + { + public: + + typedef parser parser_t; + + explicit scope_handler(parser& p) + : parser_(p) + { + parser_.state_.scope_depth++; + #ifdef exprtk_enable_debugging + const std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("%s> Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + ~scope_handler() + { + parser_.sem_.deactivate(parser_.state_.scope_depth); + parser_.state_.scope_depth--; + #ifdef exprtk_enable_debugging + const std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("<%s Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + private: + + scope_handler(const scope_handler&) exprtk_delete; + scope_handler& operator=(const scope_handler&) exprtk_delete; + + parser_t& parser_; + }; + + class stack_limit_handler + { + public: + + typedef parser parser_t; + + explicit stack_limit_handler(parser& p) + : parser_(p) + , limit_exceeded_(false) + { + if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) + { + limit_exceeded_ = true; + parser_.set_error( + make_error(parser_error::e_parser, + "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), + exprtk_error_location)); + } + } + + ~stack_limit_handler() + { + parser_.state_.stack_depth--; + } + + bool operator!() + { + return limit_exceeded_; + } + + private: + + stack_limit_handler(const stack_limit_handler&) exprtk_delete; + stack_limit_handler& operator=(const stack_limit_handler&) exprtk_delete; + + parser_t& parser_; + bool limit_exceeded_; + }; + + struct symtab_store + { + symbol_table_list_t symtab_list_; + + typedef typename symbol_table_t::local_data_t local_data_t; + typedef typename symbol_table_t::variable_ptr variable_ptr; + typedef typename symbol_table_t::function_ptr function_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; + #endif + typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; + typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; + typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + + inline bool empty() const + { + return symtab_list_.empty(); + } + + inline void clear() + { + symtab_list_.clear(); + } + + inline bool valid() const + { + if (!empty()) + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (symtab_list_[i].valid()) + return true; + } + } + + return false; + } + + inline bool valid_symbol(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_symbol(symbol); + else + return false; + } + + inline bool valid_function_name(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_function(symbol); + else + return false; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .variable_store.get(variable_name); + + if (result) break; + } + + return result; + } + + inline variable_ptr get_variable(const T& var_ref) const + { + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i).variable_store + .get_from_varptr(reinterpret_cast(&var_ref)); + + if (result) break; + } + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid_symbol(string_name)) + return reinterpret_cast(0); + + stringvar_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .stringvar_store.get(string_name); + + if (result) break; + } + + return result; + } + #endif + + inline function_ptr get_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid_function_name(vararg_function_name)) + return reinterpret_cast(0); + + vararg_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .vararg_function_store.get(vararg_function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .generic_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_string_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).string_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).overload_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid_symbol(vector_name)) + return reinterpret_cast(0); + + vector_holder_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).vector_store.get(vector_name); + + if (result) break; + } + + return result; + } + + inline bool is_constant_node(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (local_data(i).variable_store.is_constant(symbol_name)) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) + continue; + else if (local_data(i).stringvar_store.is_constant(symbol_name)) + return true; + } + + return false; + } + #endif + + inline bool symbol_exists(const std::string& symbol) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (symtab_list_[i].symbol_exists(symbol)) + return true; + } + + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().variable_store + .symbol_exists(variable_name) + ) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(stringvar_name) + ) + return true; + } + + return false; + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(symbol_name) + ) + { + return ( + local_data(i).stringvar_store.symbol_exists(symbol_name) || + local_data(i).stringvar_store.is_constant (symbol_name) + ); + + } + } + + return false; + } + #endif + + inline bool is_function(const std::string& function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(function_name) + ) + return true; + } + + return false; + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(vararg_function_name) + ) + return true; + } + + return false; + } + + inline bool is_vector(const std::string& vector_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vector_store + .symbol_exists(vector_name) + ) + return true; + } + + return false; + } + + inline std::string get_variable_name(const expression_node_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline local_data_t& local_data(const std::size_t& index = 0) + { + return symtab_list_[index].local_data(); + } + + inline const local_data_t& local_data(const std::size_t& index = 0) const + { + return symtab_list_[index].local_data(); + } + + inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) + { + return symtab_list_[index]; + } + }; + + struct parser_state + { + parser_state() + : type_check_enabled(true) + { + reset(); + } + + void reset() + { + parsing_return_stmt = false; + parsing_break_stmt = false; + return_stmt_present = false; + side_effect_present = false; + scope_depth = 0; + stack_depth = 0; + parsing_loop_stmt_count = 0; + } + + #ifndef exprtk_enable_debugging + void activate_side_effect(const std::string&) + #else + void activate_side_effect(const std::string& source) + #endif + { + if (!side_effect_present) + { + side_effect_present = true; + + exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + } + } + + bool parsing_return_stmt; + bool parsing_break_stmt; + bool return_stmt_present; + bool side_effect_present; + bool type_check_enabled; + std::size_t scope_depth; + std::size_t stack_depth; + std::size_t parsing_loop_stmt_count; + }; + + public: + + struct unknown_symbol_resolver + { + + enum usr_symbol_type + { + e_usr_unknown_type = 0, + e_usr_variable_type = 1, + e_usr_constant_type = 2 + }; + + enum usr_mode + { + e_usrmode_default = 0, + e_usrmode_extended = 1 + }; + + usr_mode mode; + + unknown_symbol_resolver(const usr_mode m = e_usrmode_default) + : mode(m) + {} + + virtual ~unknown_symbol_resolver() {} + + virtual bool process(const std::string& /*unknown_symbol*/, + usr_symbol_type& st, + T& default_value, + std::string& error_message) + { + if (e_usrmode_default != mode) + return false; + + st = e_usr_variable_type; + default_value = T(0); + error_message.clear(); + + return true; + } + + virtual bool process(const std::string& /* unknown_symbol */, + symbol_table_t& /* symbol_table */, + std::string& /* error_message */) + { + return false; + } + }; + + enum collect_type + { + e_ct_none = 0, + e_ct_variables = 1, + e_ct_functions = 2, + e_ct_assignments = 4 + }; + + enum symbol_type + { + e_st_unknown = 0, + e_st_variable = 1, + e_st_vector = 2, + e_st_vecelem = 3, + e_st_string = 4, + e_st_function = 5, + e_st_local_variable = 6, + e_st_local_vector = 7, + e_st_local_string = 8 + }; + + class dependent_entity_collector + { + public: + + typedef std::pair symbol_t; + typedef std::vector symbol_list_t; + + dependent_entity_collector(const std::size_t options = e_ct_none) + : options_(options) + , collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ) + , collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ) + , collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments) + , return_present_ (false) + , final_stmt_return_(false) + {} + + template class Sequence> + inline std::size_t symbols(Sequence& symbols_list) + { + if (!collect_variables_ && !collect_functions_) + return 0; + else if (symbol_name_list_.empty()) + return 0; + + for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) + { + details::case_normalise(symbol_name_list_[i].first); + } + + std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); + + std::unique_copy(symbol_name_list_.begin(), + symbol_name_list_.end (), + std::back_inserter(symbols_list)); + + return symbols_list.size(); + } + + template class Sequence> + inline std::size_t assignment_symbols(Sequence& assignment_list) + { + if (!collect_assignments_) + return 0; + else if (assignment_name_list_.empty()) + return 0; + + for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) + { + details::case_normalise(assignment_name_list_[i].first); + } + + std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); + + std::unique_copy(assignment_name_list_.begin(), + assignment_name_list_.end (), + std::back_inserter(assignment_list)); + + return assignment_list.size(); + } + + void clear() + { + symbol_name_list_ .clear(); + assignment_name_list_.clear(); + retparam_list_ .clear(); + return_present_ = false; + final_stmt_return_ = false; + } + + bool& collect_variables() + { + return collect_variables_; + } + + bool& collect_functions() + { + return collect_functions_; + } + + bool& collect_assignments() + { + return collect_assignments_; + } + + bool return_present() const + { + return return_present_; + } + + bool final_stmt_return() const + { + return final_stmt_return_; + } + + typedef std::vector retparam_list_t; + + retparam_list_t return_param_type_list() const + { + return retparam_list_; + } + + private: + + inline void add_symbol(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : + case e_st_local_variable : + case e_st_local_vector : + case e_st_local_string : if (collect_variables_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + case e_st_function : if (collect_functions_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; + } + } + + inline void add_assignment(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : if (collect_assignments_) + assignment_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; + } + } + + std::size_t options_; + bool collect_variables_; + bool collect_functions_; + bool collect_assignments_; + bool return_present_; + bool final_stmt_return_; + symbol_list_t symbol_name_list_; + symbol_list_t assignment_name_list_; + retparam_list_t retparam_list_; + + friend class parser; + }; + + class settings_store + { + private: + + typedef std::set disabled_entity_set_t; + typedef disabled_entity_set_t::iterator des_itr_t; + + public: + + enum settings_compilation_options + { + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64, + e_disable_vardef = 128, + e_collect_vars = 256, + e_collect_funcs = 512, + e_collect_assings = 1024, + e_disable_usr_on_rsrvd = 2048, + e_disable_zero_return = 4096 + }; + + enum settings_base_funcs + { + e_bf_unknown = 0, + e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , + e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , + e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , + e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , + e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , + e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , + e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , + e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , + e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , + e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , + e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , + e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , + e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , + e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad , + e_bf_rad2deg , e_bf_grad2deg + }; + + enum settings_control_structs + { + e_ctrl_unknown = 0, + e_ctrl_ifelse, + e_ctrl_switch, + e_ctrl_for_loop, + e_ctrl_while_loop, + e_ctrl_repeat_loop, + e_ctrl_return + }; + + enum settings_logic_opr + { + e_logic_unknown = 0, + e_logic_and, e_logic_nand , e_logic_nor , + e_logic_not, e_logic_or , e_logic_xnor, + e_logic_xor, e_logic_scand, e_logic_scor + }; + + enum settings_arithmetic_opr + { + e_arith_unknown = 0, + e_arith_add, e_arith_sub, e_arith_mul, + e_arith_div, e_arith_mod, e_arith_pow + }; + + enum settings_assignment_opr + { + e_assign_unknown = 0, + e_assign_assign, e_assign_addass, e_assign_subass, + e_assign_mulass, e_assign_divass, e_assign_modass + }; + + enum settings_inequality_opr + { + e_ineq_unknown = 0, + e_ineq_lt , e_ineq_lte, e_ineq_eq , + e_ineq_equal, e_ineq_ne , e_ineq_nequal, + e_ineq_gte , e_ineq_gt + }; + + static const std::size_t compile_all_opts = + e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + e_strength_reduction; + + settings_store(const std::size_t compile_options = compile_all_opts) + : max_stack_depth_(400) + , max_node_depth_(10000) + { + load_compile_options(compile_options); + } + + settings_store& enable_all_base_functions() + { + disabled_func_set_.clear(); + return (*this); + } + + settings_store& enable_all_control_structures() + { + disabled_ctrl_set_.clear(); + return (*this); + } + + settings_store& enable_all_logic_ops() + { + disabled_logic_set_.clear(); + return (*this); + } + + settings_store& enable_all_arithmetic_ops() + { + disabled_arithmetic_set_.clear(); + return (*this); + } + + settings_store& enable_all_assignment_ops() + { + disabled_assignment_set_.clear(); + return (*this); + } + + settings_store& enable_all_inequality_ops() + { + disabled_inequality_set_.clear(); + return (*this); + } + + settings_store& enable_local_vardef() + { + disable_vardef_ = false; + return (*this); + } + + settings_store& disable_all_base_functions() + { + std::copy(details::base_function_list, + details::base_function_list + details::base_function_list_size, + std::insert_iterator + (disabled_func_set_, disabled_func_set_.begin())); + return (*this); + } + + settings_store& disable_all_control_structures() + { + std::copy(details::cntrl_struct_list, + details::cntrl_struct_list + details::cntrl_struct_list_size, + std::insert_iterator + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + return (*this); + } + + settings_store& disable_all_logic_ops() + { + std::copy(details::logic_ops_list, + details::logic_ops_list + details::logic_ops_list_size, + std::insert_iterator + (disabled_logic_set_, disabled_logic_set_.begin())); + return (*this); + } + + settings_store& disable_all_arithmetic_ops() + { + std::copy(details::arithmetic_ops_list, + details::arithmetic_ops_list + details::arithmetic_ops_list_size, + std::insert_iterator + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + return (*this); + } + + settings_store& disable_all_assignment_ops() + { + std::copy(details::assignment_ops_list, + details::assignment_ops_list + details::assignment_ops_list_size, + std::insert_iterator + (disabled_assignment_set_, disabled_assignment_set_.begin())); + return (*this); + } + + settings_store& disable_all_inequality_ops() + { + std::copy(details::inequality_ops_list, + details::inequality_ops_list + details::inequality_ops_list_size, + std::insert_iterator + (disabled_inequality_set_, disabled_inequality_set_.begin())); + return (*this); + } + + settings_store& disable_local_vardef() + { + disable_vardef_ = true; + return (*this); + } + + bool replacer_enabled () const { return enable_replacer_; } + bool commutative_check_enabled () const { return enable_commutative_check_; } + bool joiner_enabled () const { return enable_joiner_; } + bool numeric_check_enabled () const { return enable_numeric_check_; } + bool bracket_check_enabled () const { return enable_bracket_check_; } + bool sequence_check_enabled () const { return enable_sequence_check_; } + bool strength_reduction_enabled () const { return enable_strength_reduction_; } + bool collect_variables_enabled () const { return enable_collect_vars_; } + bool collect_functions_enabled () const { return enable_collect_funcs_; } + bool collect_assignments_enabled() const { return enable_collect_assings_; } + bool vardef_disabled () const { return disable_vardef_; } + bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } + bool zero_return_disabled () const { return disable_zero_return_; } + + bool function_enabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return true; + else + return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); + } + + bool control_struct_enabled(const std::string& control_struct) const + { + if (disabled_ctrl_set_.empty()) + return true; + else + return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); + } + + bool logic_enabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return true; + else + return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); + } + + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const + { + if (disabled_logic_set_.empty()) + return true; + else + return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); + } + + bool assignment_enabled(const details::operator_type& assignment) const + { + if (disabled_assignment_set_.empty()) + return true; + else + return disabled_assignment_set_.end() == disabled_assignment_set_ + .find(assign_opr_to_string(assignment)); + } + + bool inequality_enabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return true; + else + return disabled_inequality_set_.end() == disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } + + bool function_disabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return false; + else + return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); + } + + bool control_struct_disabled(const std::string& control_struct) const + { + if (disabled_ctrl_set_.empty()) + return false; + else + return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); + } + + bool logic_disabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); + } + + bool assignment_disabled(const details::operator_type assignment_operation) const + { + if (disabled_assignment_set_.empty()) + return false; + else + return disabled_assignment_set_.end() != disabled_assignment_set_ + .find(assign_opr_to_string(assignment_operation)); + } + + bool logic_disabled(const details::operator_type logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return disabled_logic_set_.end() != disabled_logic_set_ + .find(logic_opr_to_string(logic_operation)); + } + + bool arithmetic_disabled(const details::operator_type arithmetic_operation) const + { + if (disabled_arithmetic_set_.empty()) + return false; + else + return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); + } + + bool inequality_disabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return false; + else + return disabled_inequality_set_.end() != disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } + + settings_store& disable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + disabled_func_set_.insert(details::base_function_list[bf - 1]); + } + + return (*this); + } + + settings_store& disable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); + } + + return (*this); + } + + settings_store& disable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); + } + + return (*this); + } + + settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); + } + + return (*this); + } + + settings_store& disable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); + } + + return (*this); + } + + settings_store& disable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); + } + + return (*this); + } + + settings_store& enable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); + + if (disabled_func_set_.end() != itr) + { + disabled_func_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + + if (disabled_ctrl_set_.end() != itr) + { + disabled_ctrl_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); + + if (disabled_logic_set_.end() != itr) + { + disabled_logic_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); + + if (disabled_arithmetic_set_.end() != itr) + { + disabled_arithmetic_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); + + if (disabled_assignment_set_.end() != itr) + { + disabled_assignment_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); + + if (disabled_inequality_set_.end() != itr) + { + disabled_inequality_set_.erase(itr); + } + } + + return (*this); + } + + void set_max_stack_depth(const std::size_t max_stack_depth) + { + max_stack_depth_ = max_stack_depth; + } + + void set_max_node_depth(const std::size_t max_node_depth) + { + max_node_depth_ = max_node_depth; + } + + private: + + void load_compile_options(const std::size_t compile_options) + { + enable_replacer_ = (compile_options & e_replacer ) == e_replacer; + enable_joiner_ = (compile_options & e_joiner ) == e_joiner; + enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; + enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; + enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; + enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; + enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; + enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; + enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; + enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; + disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; + disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; + disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; + } + + std::string assign_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_assign : return ":="; + case details::e_addass : return "+="; + case details::e_subass : return "-="; + case details::e_mulass : return "*="; + case details::e_divass : return "/="; + case details::e_modass : return "%="; + default : return "" ; + } + } + + std::string arith_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_add : return "+"; + case details::e_sub : return "-"; + case details::e_mul : return "*"; + case details::e_div : return "/"; + case details::e_mod : return "%"; + default : return "" ; + } + } + + std::string inequality_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_lt : return "<" ; + case details::e_lte : return "<="; + case details::e_eq : return "=="; + case details::e_equal : return "=" ; + case details::e_ne : return "!="; + case details::e_nequal: return "<>"; + case details::e_gte : return ">="; + case details::e_gt : return ">" ; + default : return "" ; + } + } + + std::string logic_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_and : return "and" ; + case details::e_or : return "or" ; + case details::e_xor : return "xor" ; + case details::e_nand : return "nand"; + case details::e_nor : return "nor" ; + case details::e_xnor : return "xnor"; + case details::e_notl : return "not" ; + default : return "" ; + } + } + + bool enable_replacer_; + bool enable_joiner_; + bool enable_numeric_check_; + bool enable_bracket_check_; + bool enable_sequence_check_; + bool enable_commutative_check_; + bool enable_strength_reduction_; + bool enable_collect_vars_; + bool enable_collect_funcs_; + bool enable_collect_assings_; + bool disable_vardef_; + bool disable_rsrvd_sym_usr_; + bool disable_zero_return_; + + disabled_entity_set_t disabled_func_set_ ; + disabled_entity_set_t disabled_ctrl_set_ ; + disabled_entity_set_t disabled_logic_set_; + disabled_entity_set_t disabled_arithmetic_set_; + disabled_entity_set_t disabled_assignment_set_; + disabled_entity_set_t disabled_inequality_set_; + + std::size_t max_stack_depth_; + std::size_t max_node_depth_; + + friend class parser; + }; + + typedef settings_store settings_t; + + parser(const settings_t& settings = settings_t()) + : settings_(settings) + , resolve_unknown_symbol_(false) + , results_context_(0) + , unknown_symbol_resolver_(reinterpret_cast(0)) + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning (disable:4355) + #endif + , sem_(*this) + #ifdef _MSC_VER + #pragma warning(pop) + #endif + , operator_joiner_2_(2) + , operator_joiner_3_(3) + , loop_runtime_check_(0) + { + init_precompilation(); + + load_operations_map (base_ops_map_ ); + load_unary_operations_map (unary_op_map_ ); + load_binary_operations_map (binary_op_map_ ); + load_inv_binary_operations_map(inv_binary_op_map_); + load_sf3_map (sf3_map_ ); + load_sf4_map (sf4_map_ ); + + expression_generator_.init_synthesize_map(); + expression_generator_.set_parser(*this); + expression_generator_.set_uom(unary_op_map_); + expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_ibom(inv_binary_op_map_); + expression_generator_.set_sf3m(sf3_map_); + expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); + } + + ~parser() {} + + inline void init_precompilation() + { + dec_.collect_variables() = + settings_.collect_variables_enabled(); + + dec_.collect_functions() = + settings_.collect_functions_enabled(); + + dec_.collect_assignments() = + settings_.collect_assignments_enabled(); + + if (settings_.replacer_enabled()) + { + symbol_replacer_.clear(); + symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); + symbol_replacer_.add_replace("false", "0", lexer::token::e_number); + helper_assembly_.token_modifier_list.clear(); + helper_assembly_.register_modifier(&symbol_replacer_); + } + + if (settings_.commutative_check_enabled()) + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + commutative_inserter_.ignore_symbol(details::reserved_words[i]); + } + + helper_assembly_.token_inserter_list.clear(); + helper_assembly_.register_inserter(&commutative_inserter_); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.token_joiner_list.clear(); + helper_assembly_.register_joiner(&operator_joiner_2_); + helper_assembly_.register_joiner(&operator_joiner_3_); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + helper_assembly_.token_scanner_list.clear(); + + if (settings_.numeric_check_enabled()) + { + helper_assembly_.register_scanner(&numeric_checker_); + } + + if (settings_.bracket_check_enabled()) + { + helper_assembly_.register_scanner(&bracket_checker_); + } + + if (settings_.sequence_check_enabled()) + { + helper_assembly_.register_scanner(&sequence_validator_ ); + helper_assembly_.register_scanner(&sequence_validator_3tkns_); + } + } + } + + inline bool compile(const std::string& expression_string, expression& expr) + { + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_.clear(); + sem_ .cleanup(); + + return_cleanup(); + + expression_generator_.set_allocator(node_allocator_); + + if (expression_string.empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR001 - Empty expression!", + exprtk_error_location)); + + return false; + } + + if (!init(expression_string)) + { + process_lexer_errors(); + return false; + } + + if (lexer().empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR002 - Empty expression!", + exprtk_error_location)); + + return false; + } + + if (!run_assemblies()) + { + return false; + } + + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); + dec_.clear(); + + lexer().begin(); + + next_token(); + + expression_node_ptr e = parse_corpus(); + + if ((0 != e) && (token_t::e_eof == current_token().type)) + { + bool* retinvk_ptr = 0; + + if (state_.return_stmt_present) + { + dec_.return_present_ = true; + + e = expression_generator_ + .return_envelope(e, results_context_, retinvk_ptr); + } + + expr.set_expression(e); + expr.set_retinvk(retinvk_ptr); + + register_local_vars(expr); + register_return_results(expr); + + return !(!expr); + } + else + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR003 - Invalid expression encountered", + exprtk_error_location)); + } + + if ((0 != e) && branch_deletable(e)) + { + destroy_node(e); + } + + dec_.clear (); + sem_.cleanup (); + return_cleanup(); + + return false; + } + } + + inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) + { + expression_t expression; + expression.register_symbol_table(symtab); + compile(expression_string,expression); + return expression; + } + + void process_lexer_errors() + { + for (std::size_t i = 0; i < lexer().size(); ++i) + { + if (lexer()[i].is_error()) + { + std::string diagnostic = "ERR004 - "; + + switch (lexer()[i].type) + { + case lexer::token::e_error : diagnostic += "General token error"; + break; + + case lexer::token::e_err_symbol : diagnostic += "Symbol error"; + break; + + case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; + break; + + case lexer::token::e_err_string : diagnostic += "Invalid string token"; + break; + + case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; + break; + + default : diagnostic += "Unknown compiler error"; + } + + set_error( + make_error(parser_error::e_lexer, + lexer()[i], + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); + } + } + } + + inline bool run_assemblies() + { + if (settings_.commutative_check_enabled()) + { + helper_assembly_.run_inserters(lexer()); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.run_joiners(lexer()); + } + + if (settings_.replacer_enabled()) + { + helper_assembly_.run_modifiers(lexer()); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + if (!helper_assembly_.run_scanners(lexer())) + { + if (helper_assembly_.error_token_scanner) + { + lexer::helper::bracket_checker* bracket_checker_ptr = 0; + lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::sequence_validator* sequence_validator_ptr = 0; + lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; + + if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + set_error( + make_error(parser_error::e_token, + bracket_checker_ptr->error_token(), + "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + exprtk_error_location)); + } + else if (0 != (numeric_checker_ptr = dynamic_cast*>(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) + { + lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; + + set_error( + make_error(parser_error::e_token, + error_token, + "ERR006 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); + } + + if (numeric_checker_ptr->error_count()) + { + numeric_checker_ptr->clear_errors(); + } + } + else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator_ptr->error_count()) + { + sequence_validator_ptr->clear_errors(); + } + } + else if (0 != (sequence_validator3_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator3_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR008 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator3_ptr->error_count()) + { + sequence_validator3_ptr->clear_errors(); + } + } + } + + return false; + } + } + + return true; + } + + inline settings_store& settings() + { + return settings_; + } + + inline parser_error::type get_error(const std::size_t& index) const + { + if (index < error_list_.size()) + return error_list_[index]; + else + throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); + } + + inline std::string error() const + { + if (!error_list_.empty()) + { + return error_list_[0].diagnostic; + } + else + return std::string("No Error"); + } + + inline std::size_t error_count() const + { + return error_list_.size(); + } + + inline dependent_entity_collector& dec() + { + return dec_; + } + + inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(old_symbol)) + return false; + else + return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); + } + + inline bool remove_replace_symbol(const std::string& symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(symbol)) + return false; + else + return symbol_replacer_.remove(symbol); + } + + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) + { + resolve_unknown_symbol_ = true; + + if (usr) + unknown_symbol_resolver_ = usr; + else + unknown_symbol_resolver_ = &default_usr_; + } + + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) + { + enable_unknown_symbol_resolver(&usr); + } + + inline void disable_unknown_symbol_resolver() + { + resolve_unknown_symbol_ = false; + unknown_symbol_resolver_ = &default_usr_; + } + + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + loop_runtime_check_ = &lrtchk; + } + + inline void clear_loop_runtime_check() + { + loop_runtime_check_ = loop_runtime_check_ptr(0); + } + + private: + + inline bool valid_base_operation(const std::string& symbol) const + { + const std::size_t length = symbol.size(); + + if ( + (length < 3) || // Shortest base op symbol length + (length > 9) // Longest base op symbol length + ) + return false; + else + return settings_.function_enabled(symbol) && + (base_ops_map_.end() != base_ops_map_.find(symbol)); + } + + inline bool valid_vararg_operation(const std::string& symbol) const + { + static const std::string s_sum = "sum" ; + static const std::string s_mul = "mul" ; + static const std::string s_avg = "avg" ; + static const std::string s_min = "min" ; + static const std::string s_max = "max" ; + static const std::string s_mand = "mand"; + static const std::string s_mor = "mor" ; + static const std::string s_multi = "~" ; + static const std::string s_mswitch = "[*]" ; + + return + ( + details::imatch(symbol,s_sum ) || + details::imatch(symbol,s_mul ) || + details::imatch(symbol,s_avg ) || + details::imatch(symbol,s_min ) || + details::imatch(symbol,s_max ) || + details::imatch(symbol,s_mand ) || + details::imatch(symbol,s_mor ) || + details::imatch(symbol,s_multi ) || + details::imatch(symbol,s_mswitch) + ) && + settings_.function_enabled(symbol); + } + + bool is_invalid_logic_operation(const details::operator_type operation) const + { + return settings_.logic_disabled(operation); + } + + bool is_invalid_arithmetic_operation(const details::operator_type operation) const + { + return settings_.arithmetic_disabled(operation); + } + + bool is_invalid_assignment_operation(const details::operator_type operation) const + { + return settings_.assignment_disabled(operation); + } + + bool is_invalid_inequality_operation(const details::operator_type operation) const + { + return settings_.inequality_disabled(operation); + } + + #ifdef exprtk_enable_debugging + inline void next_token() + { + const std::string ct_str = current_token().value; + const std::size_t ct_pos = current_token().position; + parser_helper::next_token(); + const std::string depth(2 * state_.scope_depth,' '); + exprtk_debug(("%s" + "prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", + depth.c_str(), + ct_str.c_str(), + static_cast(ct_pos), + current_token().value.c_str(), + static_cast(current_token().position), + static_cast(state_.stack_depth))); + } + #endif + + inline expression_node_ptr parse_corpus() + { + std::vector arg_list; + std::vector side_effect_list; + + scoped_vec_delete sdd((*this),arg_list); + + lexer::token begin_token; + lexer::token end_token; + + for ( ; ; ) + { + state_.side_effect_present = false; + + begin_token = current_token(); + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR009 - Invalid expression encountered", + exprtk_error_location)); + } + + return error_node(); + } + else + { + arg_list.push_back(arg); + + side_effect_list.push_back(state_.side_effect_present); + + end_token = current_token(); + + const std::string sub_expr = construct_subexpr(begin_token, end_token); + + exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", + static_cast(arg_list.size() - 1), + sub_expr.c_str())); + + exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", + static_cast(arg_list.size() - 1), + state_.side_effect_present ? "true" : "false")); + + exprtk_debug(("-------------------------------------------------\n")); + } + + if (lexer().finished()) + break; + else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + if (lexer().finished()) + break; + else + next_token(); + } + } + + if ( + !arg_list.empty() && + is_return_node(arg_list.back()) + ) + { + dec_.final_stmt_return_ = true; + } + + const expression_node_ptr result = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == result); + + return result; + } + + std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + { + std::string result = lexer().substr(begin_token.position,end_token.position); + + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } + + return result; + } + + static const precedence_level default_precedence = e_level00; + + struct state_t + { + inline void set(const precedence_level& l, + const precedence_level& r, + const details::operator_type& o) + { + left = l; + right = r; + operation = o; + } + + inline void reset() + { + left = e_level00; + right = e_level00; + operation = details::e_default; + } + + precedence_level left; + precedence_level right; + details::operator_type operation; + }; + + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) + { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + + expression_node_ptr expression = parse_branch(precedence); + + if (0 == expression) + { + return error_node(); + } + + bool break_loop = false; + + state_t current_state; + + for ( ; ; ) + { + current_state.reset(); + + switch (current_token().type) + { + case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign); break; + case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass); break; + case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass); break; + case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass); break; + case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass); break; + case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass); break; + case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap ); break; + case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt ); break; + case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte ); break; + case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq ); break; + case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne ); break; + case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte ); break; + case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt ); break; + case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add ); break; + case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub ); break; + case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div ); break; + case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul ); break; + case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod ); break; + case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow ); break; + default : if (token_t::e_symbol == current_token().type) + { + static const std::string s_and = "and" ; + static const std::string s_nand = "nand" ; + static const std::string s_or = "or" ; + static const std::string s_nor = "nor" ; + static const std::string s_xor = "xor" ; + static const std::string s_xnor = "xnor" ; + static const std::string s_in = "in" ; + static const std::string s_like = "like" ; + static const std::string s_ilike = "ilike"; + static const std::string s_and1 = "&" ; + static const std::string s_or1 = "|" ; + static const std::string s_not = "not" ; + + if (details::imatch(current_token().value,s_and)) + { + current_state.set(e_level03, e_level04, details::e_and); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03, e_level04, details::e_scand); + #else + current_state.set(e_level03, e_level04, details::e_and); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03, e_level04, details::e_nand); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01, e_level02, details::e_or); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01, e_level02, details::e_scor); + #else + current_state.set(e_level01, e_level02, details::e_or); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01, e_level02, details::e_nor); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01, e_level02, details::e_xor); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01, e_level02, details::e_xnor); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04, e_level04, details::e_in); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04, e_level04, details::e_like); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04, e_level04, details::e_ilike); + break; + } + else if (details::imatch(current_token().value,s_not)) + { + break; + } + } + + break_loop = true; + } + + if (break_loop) + { + parse_pending_string_rangesize(expression); + break; + } + else if (current_state.left < precedence) + break; + + const lexer::token prev_token = current_token(); + + next_token(); + + expression_node_ptr right_branch = error_node(); + expression_node_ptr new_expression = error_node(); + + if (is_invalid_logic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_arithmetic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_inequality_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_assignment_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + + if (0 != (right_branch = parse_expression(current_state.right))) + { + if ( + details::is_return_node(expression ) || + details::is_return_node(right_branch) + ) + { + free_node(node_allocator_, expression ); + free_node(node_allocator_, right_branch); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR014 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); + + return error_node(); + } + + new_expression = expression_generator_ + ( + current_state.operation, + expression, + right_branch + ); + } + + if (0 == new_expression) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR015 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); + } + + free_node(node_allocator_, expression ); + free_node(node_allocator_, right_branch); + + return error_node(); + } + else + { + if ( + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + (e_level00 == precedence) + ) + { + expression = parse_ternary_conditional_statement(new_expression); + } + else + expression = new_expression; + + parse_pending_string_rangesize(expression); + } + } + + if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), + exprtk_error_location)); + + free_node(node_allocator_,expression); + + return error_node(); + } + + return expression; + } + + bool simplify_unary_negation_branch(expression_node_ptr& node) + { + { + typedef details::unary_branch_node > ubn_t; + ubn_t* n = dynamic_cast(node); + + if (n) + { + expression_node_ptr un_r = n->branch(0); + n->release(); + free_node(node_allocator_,node); + node = un_r; + + return true; + } + } + + { + typedef details::unary_variable_node > uvn_t; + + uvn_t* n = dynamic_cast(node); + + if (n) + { + const T& v = n->v(); + expression_node_ptr return_node = error_node(); + + if ( + (0 != (return_node = symtab_store_.get_variable(v))) || + (0 != (return_node = sem_ .get_variable(v))) + ) + { + free_node(node_allocator_,node); + node = return_node; + + return true; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR017 - Failed to find variable node in symbol table", + exprtk_error_location)); + + free_node(node_allocator_,node); + + return false; + } + } + } + + return false; + } + + static inline expression_node_ptr error_node() + { + return reinterpret_cast(0); + } + + struct scoped_expression_delete + { + scoped_expression_delete(parser& pr, expression_node_ptr& expression) + : delete_ptr(true) + , parser_(pr) + , expression_(expression) + {} + + ~scoped_expression_delete() + { + if (delete_ptr) + { + free_node(parser_.node_allocator_, expression_); + } + } + + bool delete_ptr; + parser& parser_; + expression_node_ptr& expression_; + + private: + + scoped_expression_delete(const scoped_expression_delete&) exprtk_delete; + scoped_expression_delete& operator=(const scoped_expression_delete&) exprtk_delete; + }; + + template + struct scoped_delete + { + typedef Type* ptr_t; + + scoped_delete(parser& pr, ptr_t& p) + : delete_ptr(true) + , parser_(pr) + , p_(&p) + {} + + scoped_delete(parser& pr, ptr_t (&p)[N]) + : delete_ptr(true) + , parser_(pr) + , p_(&p[0]) + {} + + ~scoped_delete() + { + if (delete_ptr) + { + for (std::size_t i = 0; i < N; ++i) + { + free_node(parser_.node_allocator_, p_[i]); + } + } + } + + bool delete_ptr; + parser& parser_; + ptr_t* p_; + + private: + + scoped_delete(const scoped_delete&) exprtk_delete; + scoped_delete& operator=(const scoped_delete&) exprtk_delete; + }; + + template + struct scoped_deq_delete + { + typedef Type* ptr_t; + + scoped_deq_delete(parser& pr, std::deque& deq) + : delete_ptr(true) + , parser_(pr) + , deq_(deq) + {} + + ~scoped_deq_delete() + { + if (delete_ptr && !deq_.empty()) + { + for (std::size_t i = 0; i < deq_.size(); ++i) + { + free_node(parser_.node_allocator_,deq_[i]); + } + + deq_.clear(); + } + } + + bool delete_ptr; + parser& parser_; + std::deque& deq_; + + private: + + scoped_deq_delete(const scoped_deq_delete&) exprtk_delete; + scoped_deq_delete& operator=(const scoped_deq_delete&) exprtk_delete; + }; + + template + struct scoped_vec_delete + { + typedef Type* ptr_t; + + scoped_vec_delete(parser& pr, std::vector& vec) + : delete_ptr(true) + , parser_(pr) + , vec_(vec) + {} + + ~scoped_vec_delete() + { + if (delete_ptr && !vec_.empty()) + { + for (std::size_t i = 0; i < vec_.size(); ++i) + { + free_node(parser_.node_allocator_,vec_[i]); + } + + vec_.clear(); + } + } + + bool delete_ptr; + parser& parser_; + std::vector& vec_; + + private: + + scoped_vec_delete(const scoped_vec_delete&) exprtk_delete; + scoped_vec_delete& operator=(const scoped_vec_delete&) exprtk_delete; + }; + + struct scoped_bool_negator + { + explicit scoped_bool_negator(bool& bb) + : b(bb) + { b = !b; } + + ~scoped_bool_negator() + { b = !b; } + + bool& b; + }; + + struct scoped_bool_or_restorer + { + explicit scoped_bool_or_restorer(bool& bb) + : b(bb) + , original_value_(bb) + {} + + ~scoped_bool_or_restorer() + { + b = b || original_value_; + } + + bool& b; + bool original_value_; + }; + + struct scoped_inc_dec + { + explicit scoped_inc_dec(std::size_t& v) + : v_(v) + { ++v_; } + + ~scoped_inc_dec() + { + assert(v_ > 0); + --v_; + } + + std::size_t& v_; + }; + + inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) + { + expression_node_ptr func_node = reinterpret_cast(0); + + switch (function->param_count) + { + case 0 : func_node = parse_function_call_0 (function,function_name); break; + case 1 : func_node = parse_function_call< 1>(function,function_name); break; + case 2 : func_node = parse_function_call< 2>(function,function_name); break; + case 3 : func_node = parse_function_call< 3>(function,function_name); break; + case 4 : func_node = parse_function_call< 4>(function,function_name); break; + case 5 : func_node = parse_function_call< 5>(function,function_name); break; + case 6 : func_node = parse_function_call< 6>(function,function_name); break; + case 7 : func_node = parse_function_call< 7>(function,function_name); break; + case 8 : func_node = parse_function_call< 8>(function,function_name); break; + case 9 : func_node = parse_function_call< 9>(function,function_name); break; + case 10 : func_node = parse_function_call<10>(function,function_name); break; + case 11 : func_node = parse_function_call<11>(function,function_name); break; + case 12 : func_node = parse_function_call<12>(function,function_name); break; + case 13 : func_node = parse_function_call<13>(function,function_name); break; + case 14 : func_node = parse_function_call<14>(function,function_name); break; + case 15 : func_node = parse_function_call<15>(function,function_name); break; + case 16 : func_node = parse_function_call<16>(function,function_name); break; + case 17 : func_node = parse_function_call<17>(function,function_name); break; + case 18 : func_node = parse_function_call<18>(function,function_name); break; + case 19 : func_node = parse_function_call<19>(function,function_name); break; + case 20 : func_node = parse_function_call<20>(function,function_name); break; + default : { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR018 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + if (func_node) + return func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR019 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + template + inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (0 == NumberofParameters) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); + + return error_node(); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + expression_node_ptr branch[NumberofParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberofParameters, reinterpret_cast(0)); + + scoped_delete sd((*this),branch); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR021 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + + for (int i = 0; i < static_cast(NumberofParameters); ++i) + { + branch[i] = parse_expression(); + + if (0 == branch[i]) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (i < static_cast(NumberofParameters - 1)) + { + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR023 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR024 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + else + result = expression_generator_.function(function,branch); + + sd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) + { + expression_node_ptr result = expression_generator_.function(function); + + state_.side_effect_present = function->has_side_effects(); + + next_token(); + + if ( + token_is(token_t::e_lbracket) && + !token_is(token_t::e_rbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); + + free_node(node_allocator_,result); + + return error_node(); + } + else + return result; + } + + template + inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") + { + std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast(0)); + + scoped_delete sd((*this),param_list); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR026 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return 0; + } + + if (token_is(token_t::e_rbracket, e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); + + return 0; + } + + std::size_t param_index = 0; + + for (; param_index < MaxNumberofParameters; ++param_index) + { + param_list[param_index] = parse_expression(); + + if (0 == param_list[param_index]) + return 0; + else if (token_is(token_t::e_rbracket)) + { + sd.delete_ptr = false; + break; + } + else if (token_is(token_t::e_comma)) + continue; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return 0; + } + } + + if (sd.delete_ptr) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); + + return 0; + } + + return (param_index + 1); + } + + inline expression_node_ptr parse_base_operation() + { + typedef std::pair map_range_t; + + const std::string operation_name = current_token().value; + const token_t diagnostic_token = current_token(); + + map_range_t itr_range = base_ops_map_.equal_range(operation_name); + + if (0 == std::distance(itr_range.first,itr_range.second)) + { + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR030 - No entry found for base operation: " + operation_name, + exprtk_error_location)); + + return error_node(); + } + + static const std::size_t MaxNumberofParameters = 4; + expression_node_ptr param_list[MaxNumberofParameters] = {0}; + + const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); + + if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) + { + for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) + { + const details::base_operation_t& operation = itr->second; + + if (operation.num_params == parameter_count) + { + switch (parameter_count) + { + #define base_opr_case(N) \ + case N : { \ + expression_node_ptr pl##N[N] = {0}; \ + std::copy(param_list, param_list + N, pl##N); \ + lodge_symbol(operation_name, e_st_function); \ + return expression_generator_(operation.type, pl##N); \ + } \ + + base_opr_case(1) + base_opr_case(2) + base_opr_case(3) + base_opr_case(4) + #undef base_opr_case + } + } + } + } + + for (std::size_t i = 0; i < MaxNumberofParameters; ++i) + { + free_node(node_allocator_, param_list[i]); + } + + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); + + return error_node(); + } + + inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) + { + // Parse: [if][(][condition][,][consequent][,][alternative][)] + + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR032 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); + result = false; + } + else if (0 == (consequent = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR033 - Failed to parse consequent for if-statement", + exprtk_error_location)); + result = false; + } + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR034 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR035 - Failed to parse alternative for if-statement", + exprtk_error_location)); + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR036 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR037 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR038 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) + { + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (consequent = parse_multi_sequence("if-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR039 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) + ) + { + next_token(); + } + + if (0 != (consequent = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR040 - Expected ';' at the end of the consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR041 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + + if (result) + { + if (details::imatch(current_token().value,"else")) + { + next_token(); + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (alternative = parse_multi_sequence("else-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR042 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + + result = false; + } + } + else if (details::imatch(current_token().value,"if")) + { + if (0 == (alternative = parse_conditional_statement())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR043 - Failed to parse body of if-else statement", + exprtk_error_location)); + + result = false; + } + } + else if (0 != (alternative = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR044 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR045 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + + result = false; + } + } + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR046 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR047 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_conditional_statement() + { + expression_node_ptr condition = error_node(); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR048 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR049 - Failed to parse condition for if-statement", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) + { + // if (x,y,z) + return parse_conditional_statement_01(condition); + } + else if (token_is(token_t::e_rbracket)) + { + /* + 00. if (x) y; + 01. if (x) y; else z; + 02. if (x) y; else {z0; ... zn;} + 03. if (x) y; else if (z) w; + 04. if (x) y; else if (z) w; else u; + 05. if (x) y; else if (z) w; else {u0; ... un;} + 06. if (x) y; else if (z) {w0; ... wn;} + 07. if (x) {y0; ... yn;} + 08. if (x) {y0; ... yn;} else z; + 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + 10. if (x) {y0; ... yn;} else if (z) w; + 11. if (x) {y0; ... yn;} else if (z) w; else u; + 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + */ + return parse_conditional_statement_02(condition); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR050 - Invalid if-statement", + exprtk_error_location)); + + free_node(node_allocator_,condition); + + return error_node(); + } + + inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) + { + // Parse: [condition][?][consequent][:][alternative] + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (0 == condition) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR051 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_ternary)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR052 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); + + result = false; + } + else if (0 == (consequent = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR053 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR054 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); + + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR055 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); + + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR056 - Return types of ternary differ: string/non-string", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR057 - Return types of ternary differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_not_statement() + { + if (settings_.logic_disabled("not")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR058 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); + + return error_node(); + } + + return parse_base_operation(); + } + + inline expression_node_ptr parse_while_loop() + { + // Parse: [while][(][test expr][)][{][expression][}] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + expression_node_ptr result_node = error_node(); + + bool result = true; + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR059 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR060 - Failed to parse condition for while-loop", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR061 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); + + result = false; + } + + brkcnt_list_.push_front(false); + + if (result) + { + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + if (0 == (branch = parse_multi_sequence("while-loop"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR062 - Failed to parse body of while-loop")); + result = false; + } + else if (0 == (result_node = expression_generator_.while_loop(condition, + branch, + brkcnt_list_.front()))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR063 - Failed to synthesize while-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + free_node(node_allocator_, branch ); + free_node(node_allocator_, condition ); + free_node(node_allocator_, result_node); + + brkcnt_list_.pop_front(); + + return error_node(); + } + else + return result_node; + } + + inline expression_node_ptr parse_repeat_until_loop() + { + // Parse: [repeat][{][expression][}][until][(][test expr][)] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + next_token(); + + std::vector arg_list; + std::vector side_effect_list; + + scoped_vec_delete sdd((*this),arg_list); + + brkcnt_list_.push_front(false); + + if (details::imatch(current_token().value,"until")) + { + next_token(); + branch = node_allocator_.allocate >(); + } + else + { + const token_t::token_type seperator = token_t::e_eof; + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (details::imatch(current_token().value,"until")) + { + next_token(); + break; + } + + const bool is_next_until = peek_token_is(token_t::e_symbol) && + peek_token_is("until"); + + if (!token_is(seperator) && is_next_until) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR064 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", + exprtk_error_location)); + + return error_node(); + } + + if (details::imatch(current_token().value,"until")) + { + next_token(); + break; + } + } + + branch = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == branch); + + if (sdd.delete_ptr) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR065 - Failed to parse body of repeat until loop", + exprtk_error_location)); + + return error_node(); + } + } + + if (!token_is(token_t::e_lbracket)) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR066 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR067 - Failed to parse condition for repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR068 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_, branch ); + free_node(node_allocator_, condition); + + brkcnt_list_.pop_front(); + + return error_node(); + } + + expression_node_ptr result; + + result = expression_generator_ + .repeat_until_loop(condition, branch, brkcnt_list_.front()); + + if (0 == result) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR069 - Failed to synthesize repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,condition); + + brkcnt_list_.pop_front(); + + return error_node(); + } + else + { + brkcnt_list_.pop_front(); + return result; + } + } + + inline expression_node_ptr parse_for_loop() + { + expression_node_ptr initialiser = error_node(); + expression_node_ptr condition = error_node(); + expression_node_ptr incrementor = error_node(); + expression_node_ptr loop_body = error_node(); + + scope_element* se = 0; + bool result = true; + + next_token(); + + scope_handler sh(*this); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR070 - Expected '(' at start of for-loop", + exprtk_error_location)); + + return error_node(); + } + + if (!token_is(token_t::e_eof)) + { + if ( + !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && + details::imatch(current_token().value,"var") + ) + { + next_token(); + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR071 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); + + return error_node(); + } + else if (!peek_token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR072 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); + + return error_node(); + } + + const std::string loop_counter_symbol = current_token().value; + + se = &sem_.get_element(loop_counter_symbol); + + if ((se->name == loop_counter_symbol) && se->active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR073 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); + + return error_node(); + } + else if (!symtab_store_.is_variable(loop_counter_symbol)) + { + if ( + !se->active && + (se->name == loop_counter_symbol) && + (se->type == scope_element::e_variable) + ) + { + se->active = true; + se->ref_count++; + } + else + { + scope_element nse; + nse.name = loop_counter_symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR074 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + result = false; + } + else + { + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + + state_.activate_side_effect("parse_for_loop()"); + } + } + } + } + + if (0 == (initialiser = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR075 - Failed to parse initialiser of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR076 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!token_is(token_t::e_eof)) + { + if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR077 - Failed to parse condition of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR078 - Expected ';' after condition section of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!token_is(token_t::e_rbracket)) + { + if (0 == (incrementor = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR079 - Failed to parse incrementor of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR080 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (result) + { + brkcnt_list_.push_front(false); + + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + if (0 == (loop_body = parse_multi_sequence("for-loop"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR081 - Failed to parse body of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + if (se) + { + se->ref_count--; + } + + free_node(node_allocator_, initialiser); + free_node(node_allocator_, condition ); + free_node(node_allocator_, incrementor); + free_node(node_allocator_, loop_body ); + + if (!brkcnt_list_.empty()) + { + brkcnt_list_.pop_front(); + } + + return error_node(); + } + else + { + expression_node_ptr result_node = + expression_generator_.for_loop(initialiser, + condition, + incrementor, + loop_body, + brkcnt_list_.front()); + brkcnt_list_.pop_front(); + + return result_node; + } + } + + inline expression_node_ptr parse_switch_statement() + { + std::vector arg_list; + expression_node_ptr result = error_node(); + + if (!details::imatch(current_token().value,"switch")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR082 - Expected keyword 'switch'", + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete svd((*this),arg_list); + + next_token(); + + if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR083 - Expected '{' for call to switch statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr default_statement = error_node(); + + scoped_expression_delete defstmt_delete((*this), default_statement); + + for ( ; ; ) + { + if (details::imatch("case",current_token().value)) + { + next_token(); + + expression_node_ptr condition = parse_expression(); + + if (0 == condition) + return error_node(); + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR084 - Expected ':' for case of switch statement", + exprtk_error_location)); + + free_node(node_allocator_, condition); + + return error_node(); + } + + expression_node_ptr consequent = parse_expression(); + + if (0 == consequent) + { + free_node(node_allocator_, condition); + + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR085 - Expected ';' at end of case for switch statement", + exprtk_error_location)); + + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + } + else + { + arg_list.push_back(condition ); + arg_list.push_back(consequent); + } + + } + else if (details::imatch("default",current_token().value)) + { + if (0 != default_statement) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR086 - Multiple default cases for switch statement", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR087 - Expected ':' for default of switch statement", + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + default_statement = parse_multi_sequence("switch-default"); + else + default_statement = parse_expression(); + + if (0 == default_statement) + return error_node(); + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR088 - Expected ';' at end of default for switch statement", + exprtk_error_location)); + + return error_node(); + } + } + else if (token_is(token_t::e_rcrlbracket)) + break; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR089 - Expected '}' at end of switch statement", + exprtk_error_location)); + + return error_node(); + } + } + + const bool default_statement_present = (0 != default_statement); + + if (default_statement_present) + { + arg_list.push_back(default_statement); + } + + result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); + + svd.delete_ptr = (0 == result); + defstmt_delete.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_multi_switch_statement() + { + std::vector arg_list; + + if (!details::imatch(current_token().value,"[*]")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR090 - Expected token '[*]'", + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete svd((*this),arg_list); + + next_token(); + + if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR091 - Expected '{' for call to [*] statement", + exprtk_error_location)); + + return error_node(); + } + + for ( ; ; ) + { + if (!details::imatch("case",current_token().value)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR092 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + + expression_node_ptr condition = parse_expression(); + + if (0 == condition) + return error_node(); + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR093 - Expected ':' for case of [*] statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr consequent = parse_expression(); + + if (0 == consequent) + return error_node(); + + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR094 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + } + else + { + arg_list.push_back(condition ); + arg_list.push_back(consequent); + } + + if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) + { + break; + } + } + + if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR095 - Expected '}' at end of [*] statement", + exprtk_error_location)); + + return error_node(); + } + + const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); + + svd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_vararg_function() + { + std::vector arg_list; + + details::operator_type opt_type = details::e_default; + const std::string symbol = current_token().value; + + if (details::imatch(symbol,"~")) + { + next_token(); + return parse_multi_sequence(); + } + else if (details::imatch(symbol,"[*]")) + { + return parse_multi_switch_statement(); + } + else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; + else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; + else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; + else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; + else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; + else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; + else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR096 - Unsupported vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete sdd((*this),arg_list); + + lodge_symbol(symbol, e_st_function); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR097 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR098 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + } + + const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) + { + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR099 - Expected '[' as start of string range definition", + exprtk_error_location)); + + free_node(node_allocator_,expression); + + return error_node(); + } + else if (token_is(token_t::e_rsqrbracket)) + { + return node_allocator_.allocate >(expression); + } + + range_t rp; + + if (!parse_range(rp,true)) + { + free_node(node_allocator_,expression); + + return error_node(); + } + + expression_node_ptr result = expression_generator_(expression,rp); + + if (0 == result) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR100 - Failed to generate string range node", + exprtk_error_location)); + + free_node(node_allocator_,expression); + rp.free(); + } + + rp.clear(); + + return result; + } + #else + inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) + { + return error_node(); + } + #endif + + inline void parse_pending_string_rangesize(expression_node_ptr& expression) + { + // Allow no more than 100 range calls, eg: s[][][]...[][] + const std::size_t max_rangesize_parses = 100; + + std::size_t i = 0; + + while + ( + (0 != expression) && + (i++ < max_rangesize_parses) && + error_list_.empty() && + is_generally_string_node(expression) && + token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) + ) + { + expression = parse_string_range_statement(expression); + } + } + + template class Sequence> + inline expression_node_ptr simplify(Sequence& expression_list, + Sequence& side_effect_list, + const bool specialise_on_final_type = false) + { + if (expression_list.empty()) + return error_node(); + else if (1 == expression_list.size()) + return expression_list[0]; + + Sequence tmp_expression_list; + + bool return_node_present = false; + + for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) + { + if (is_variable_node(expression_list[i])) + continue; + else if ( + is_return_node (expression_list[i]) || + is_break_node (expression_list[i]) || + is_continue_node(expression_list[i]) + ) + { + tmp_expression_list.push_back(expression_list[i]); + + // Remove all subexpressions after first short-circuit + // node has been encountered. + + for (std::size_t j = i + 1; j < expression_list.size(); ++j) + { + free_node(node_allocator_,expression_list[j]); + } + + return_node_present = true; + + break; + } + else if ( + is_constant_node(expression_list[i]) || + is_null_node (expression_list[i]) || + !side_effect_list[i] + ) + { + free_node(node_allocator_,expression_list[i]); + continue; + } + else + tmp_expression_list.push_back(expression_list[i]); + } + + if (!return_node_present) + { + tmp_expression_list.push_back(expression_list.back()); + } + + expression_list.swap(tmp_expression_list); + + if (tmp_expression_list.size() > expression_list.size()) + { + exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", + static_cast(tmp_expression_list.size()), + static_cast(expression_list .size()))); + } + + if ( + return_node_present || + side_effect_list.back() || + (expression_list.size() > 1) + ) + state_.activate_side_effect("simplify()"); + + if (1 == expression_list.size()) + return expression_list[0]; + else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) + return expression_generator_.vararg_function(details::e_smulti,expression_list); + else + return expression_generator_.vararg_function(details::e_multi,expression_list); + } + + inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + { + token_t::token_type close_bracket = token_t::e_rcrlbracket; + token_t::token_type seperator = token_t::e_eof; + + if (!token_is(token_t::e_lcrlbracket)) + { + if (token_is(token_t::e_lbracket)) + { + close_bracket = token_t::e_rbracket; + seperator = token_t::e_comma; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR101 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); + + return error_node(); + } + } + else if (token_is(token_t::e_rcrlbracket)) + { + return node_allocator_.allocate >(); + } + + std::vector arg_list; + std::vector side_effect_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd((*this),arg_list); + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (token_is(close_bracket)) + break; + + const bool is_next_close = peek_token_is(close_bracket); + + if (!token_is(seperator) && is_next_close) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR102 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); + + return error_node(); + } + + if (token_is(close_bracket)) + break; + } + + result = simplify(arg_list,side_effect_list,source.empty()); + + sdd.delete_ptr = (0 == result); + return result; + } + + inline bool parse_range(range_t& rp, const bool skip_lsqr = false) + { + // Examples of valid ranges: + // 1. [1:5] -> 1..5 + // 2. [ :5] -> 0..5 + // 3. [1: ] -> 1..end + // 4. [x:y] -> x..y where x <= y + // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 + // 6. [ :y] -> 0..y where 0 <= y + // 7. [x: ] -> x..end where x <= end + + rp.clear(); + + if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR103 - Expected '[' for start of range", + exprtk_error_location)); + + return false; + } + + if (token_is(token_t::e_colon)) + { + rp.n0_c.first = true; + rp.n0_c.second = 0; + rp.cache.first = 0; + } + else + { + expression_node_ptr r0 = parse_expression(); + + if (0 == r0) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR104 - Failed parse begin section of range", + exprtk_error_location)); + + return false; + } + else if (is_constant_node(r0)) + { + const T r0_value = r0->value(); + + if (r0_value >= T(0)) + { + rp.n0_c.first = true; + rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); + rp.cache.first = rp.n0_c.second; + } + + free_node(node_allocator_,r0); + + if (r0_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR105 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); + + return false; + } + } + else + { + rp.n0_e.first = true; + rp.n0_e.second = r0; + } + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR106 - Expected ':' for break in range", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + + if (token_is(token_t::e_rsqrbracket)) + { + rp.n1_c.first = true; + rp.n1_c.second = std::numeric_limits::max(); + } + else + { + expression_node_ptr r1 = parse_expression(); + + if (0 == r1) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR107 - Failed parse end section of range", + exprtk_error_location)); + + rp.free(); + + return false; + } + else if (is_constant_node(r1)) + { + const T r1_value = r1->value(); + + if (r1_value >= T(0)) + { + rp.n1_c.first = true; + rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); + rp.cache.second = rp.n1_c.second; + } + + free_node(node_allocator_,r1); + + if (r1_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR108 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + else + { + rp.n1_e.first = true; + rp.n1_e.second = r1; + } + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR109 - Expected ']' for start of range", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + + if (rp.const_range()) + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + bool rp_result = false; + + try + { + rp_result = rp(r0, r1); + } + catch (std::runtime_error&) + {} + + if (!rp_result || (r0 > r1)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR110 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); + + return false; + } + } + + return true; + } + + inline void lodge_symbol(const std::string& symbol, + const symbol_type st) + { + dec_.add_symbol(symbol,st); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string() + { + const std::string symbol = current_token().value; + + typedef details::stringvar_node* strvar_node_t; + + expression_node_ptr result = error_node(); + strvar_node_t const_str_node = static_cast(0); + + scope_element& se = sem_.get_active_element(symbol); + + if (scope_element::e_string == se.type) + { + se.active = true; + result = se.str_node; + lodge_symbol(symbol, e_st_local_string); + } + else + { + if (!symtab_store_.is_conststr_stringvar(symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR111 - Unknown string symbol", + exprtk_error_location)); + + return error_node(); + } + + result = symtab_store_.get_stringvar(symbol); + + if (symtab_store_.is_constant_string(symbol)) + { + const_str_node = static_cast(result); + result = expression_generator_(const_str_node->str()); + } + + lodge_symbol(symbol, e_st_string); + } + + if (peek_token_is(token_t::e_lsqrbracket)) + { + next_token(); + + if (peek_token_is(token_t::e_rsqrbracket)) + { + next_token(); + next_token(); + + if (const_str_node) + { + free_node(node_allocator_,result); + + return expression_generator_(T(const_str_node->size())); + } + else + return node_allocator_.allocate > + (static_cast*>(result)->ref()); + } + + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + + return error_node(); + } + else if (const_str_node) + { + free_node(node_allocator_,result); + result = expression_generator_(const_str_node->ref(),rp); + } + else + result = expression_generator_(static_cast*> + (result)->ref(), rp); + + if (result) + rp.clear(); + } + else + next_token(); + + return result; + } + #else + inline expression_node_ptr parse_string() + { + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_const_string() + { + const std::string const_str = current_token().value; + expression_node_ptr result = expression_generator_(const_str); + + if (peek_token_is(token_t::e_lsqrbracket)) + { + next_token(); + + if (peek_token_is(token_t::e_rsqrbracket)) + { + next_token(); + next_token(); + + free_node(node_allocator_,result); + + return expression_generator_(T(const_str.size())); + } + + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + rp.free(); + + return error_node(); + } + + free_node(node_allocator_,result); + + if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) + { + rp.n1_c.second = const_str.size() - 1; + rp.cache.second = rp.n1_c.second; + } + + if ( + (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || + (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR112 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); + + rp.free(); + + return error_node(); + } + + result = expression_generator_(const_str,rp); + + if (result) + rp.clear(); + } + else + next_token(); + + return result; + } + #else + inline expression_node_ptr parse_const_string() + { + return error_node(); + } + #endif + + inline expression_node_ptr parse_vector() + { + const std::string symbol = current_token().value; + + vector_holder_ptr vec = vector_holder_ptr(0); + + const scope_element& se = sem_.get_active_element(symbol); + + if ( + !details::imatch(se.name, symbol) || + (se.depth > state_.scope_depth) || + (scope_element::e_vector != se.type) + ) + { + if (0 == (vec = symtab_store_.get_vector(symbol))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR113 - Symbol '" + symbol+ " not a vector", + exprtk_error_location)); + + return error_node(); + } + } + else + vec = se.vec_node; + + expression_node_ptr index_expr = error_node(); + + next_token(); + + if (!token_is(token_t::e_lsqrbracket)) + { + return node_allocator_.allocate(vec); + } + else if (token_is(token_t::e_rsqrbracket)) + { + return expression_generator_(T(vec->size())); + } + else if (0 == (index_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR114 - Failed to parse index for vector: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR115 - Expected ']' for index of vector: '" + symbol + "'", + exprtk_error_location)); + + free_node(node_allocator_,index_expr); + + return error_node(); + } + + // Perform compile-time range check + if (details::is_constant_node(index_expr)) + { + const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); + const std::size_t vec_size = vec->size(); + + if (index >= vec_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR116 - Index of " + details::to_str(index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vec_size), + exprtk_error_location)); + + free_node(node_allocator_,index_expr); + + return error_node(); + } + } + + return expression_generator_.vector_element(symbol, vec, index_expr); + } + + inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) + { + std::vector arg_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd((*this),arg_list); + + next_token(); + + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR117 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR118 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); + + return error_node(); + } + } + } + } + else if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR119 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + + if (arg_list.size() < vararg_function->min_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR120 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", + exprtk_error_location)); + + return error_node(); + } + else if (arg_list.size() > vararg_function->max_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR121 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); + + return error_node(); + } + + result = expression_generator_.vararg_function_call(vararg_function,arg_list); + + sdd.delete_ptr = (0 == result); + + return result; + } + + class type_checker + { + public: + + enum return_type_t + { + e_overload = ' ', + e_numeric = 'T', + e_string = 'S' + }; + + struct function_prototype_t + { + return_type_t return_type; + std::string param_seq; + }; + + typedef parser parser_t; + typedef std::vector function_definition_list_t; + + type_checker(parser_t& p, + const std::string& func_name, + const std::string& func_prototypes, + const return_type_t default_return_type) + : invalid_state_(true) + , parser_(p) + , function_name_(func_name) + , default_return_type_(default_return_type) + { + parse_function_prototypes(func_prototypes); + } + + bool verify(const std::string& param_seq, std::size_t& pseq_index) + { + if (function_definition_list_.empty()) + return true; + + std::vector > error_list; + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + details::char_t diff_value = 0; + std::size_t diff_index = 0; + + const bool result = details::sequence_match(function_definition_list_[i].param_seq, + param_seq, + diff_index, diff_value); + + if (result) + { + pseq_index = i; + return true; + } + else + error_list.push_back(std::make_pair(diff_index, diff_value)); + } + + if (1 == error_list.size()) + { + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR122 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); + } + else + { + // find first with largest diff_index; + std::size_t max_diff_index = 0; + + for (std::size_t i = 1; i < error_list.size(); ++i) + { + if (error_list[i].first > error_list[max_diff_index].first) + { + max_diff_index = i; + } + } + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR123 - Failed parameter type check for function '" + function_name_ + "', " + "Best match: '" + function_definition_list_[max_diff_index].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); + } + + return false; + } + + std::size_t paramseq_count() const + { + return function_definition_list_.size(); + } + + std::string paramseq(const std::size_t& index) const + { + return function_definition_list_[index].param_seq; + } + + return_type_t return_type(const std::size_t& index) const + { + return function_definition_list_[index].return_type; + } + + bool invalid() const + { + return !invalid_state_; + } + + bool allow_zero_parameters() const + { + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) + { + return true; + } + } + + return false; + } + + private: + + std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const + { + std::string::const_iterator current_begin = param_seq.begin(); + std::string::const_iterator iter = param_seq.begin(); + + std::vector result; + + while (iter != param_seq.end()) + { + if (*iter == delimiter) + { + result.push_back(std::string(current_begin, iter)); + current_begin = ++iter; + } + else + ++iter; + } + + if (current_begin != iter) + { + result.push_back(std::string(current_begin, iter)); + } + + return result; + } + + inline bool is_valid_token(std::string param_seq, + function_prototype_t& funcproto) const + { + // Determine return type + funcproto.return_type = default_return_type_; + + if (param_seq.size() > 2) + { + if (':' == param_seq[1]) + { + // Note: Only overloaded igeneric functions can have return + // type definitions. + if (type_checker::e_overload != default_return_type_) + return false; + + switch (param_seq[0]) + { + case 'T' : funcproto.return_type = type_checker::e_numeric; + break; + + case 'S' : funcproto.return_type = type_checker::e_string; + break; + + default : return false; + } + + param_seq.erase(0,2); + } + } + + if ( + (std::string::npos != param_seq.find("?*")) || + (std::string::npos != param_seq.find("**")) + ) + { + return false; + } + else if ( + (std::string::npos == param_seq.find_first_not_of("STV*?|")) || + ("Z" == param_seq) + ) + { + funcproto.param_seq = param_seq; + return true; + } + + return false; + } + + void parse_function_prototypes(const std::string& func_prototypes) + { + if (func_prototypes.empty()) + return; + + std::vector param_seq_list = split_param_seq(func_prototypes); + + typedef std::map param_seq_map_t; + param_seq_map_t param_seq_map; + + for (std::size_t i = 0; i < param_seq_list.size(); ++i) + { + function_prototype_t func_proto; + + if (!is_valid_token(param_seq_list[i], func_proto)) + { + invalid_state_ = false; + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR124 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); + return; + } + + param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); + + if (param_seq_map.end() != seq_itr) + { + invalid_state_ = false; + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR125 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + + "pseq_idx[" + details::to_str(i) + "] " + + "param seq: " + param_seq_list[i], + exprtk_error_location)); + return; + } + + function_definition_list_.push_back(func_proto); + } + } + + type_checker(const type_checker&) exprtk_delete; + type_checker& operator=(const type_checker&) exprtk_delete; + + bool invalid_state_; + parser_t& parser_; + std::string function_name_; + const return_type_t default_return_type_; + function_definition_list_t function_definition_list_; + }; + + inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) + { + std::vector arg_list; + + scoped_vec_delete sdd((*this),arg_list); + + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if (tc.invalid()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR126 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR127 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is assumed to be a scalar returning expression + param_type_list += 'T'; + + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR128 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + } + } + } + else if ( + !function->parameter_sequence.empty() && + function->allow_zero_parameters () && + !tc .allow_zero_parameters () + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR129 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + + std::size_t param_seq_index = 0; + + if ( + state_.type_check_enabled && + !tc.verify(param_type_list, param_seq_index) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR130 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + + sdd.delete_ptr = (0 == result); + + return result; + } + + inline bool parse_igeneric_function_params(std::string& param_type_list, + std::vector& arg_list, + const std::string& function_name, + igeneric_function* function, + const type_checker& tc) + { + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR131 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return false; + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return false; + + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is a scalar returning expression + param_type_list += 'T'; + + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR132 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); + + return false; + } + } + } + + return true; + } + else + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR133 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + + sdd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_overload_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR134 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (type_checker::e_numeric == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + } + else if (type_checker::e_string == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR135 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); + } + + sdd.delete_ptr = (0 == result); + return result; + } + #endif + + template + struct parse_special_function_impl + { + static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, const std::string& sf_name) + { + expression_node_ptr branch[NumberOfParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); + + scoped_delete sd(p,branch); + + p.next_token(); + + if (!p.token_is(token_t::e_lbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR136 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); + + return error_node(); + } + + for (std::size_t i = 0; i < NumberOfParameters; ++i) + { + branch[i] = p.parse_expression(); + + if (0 == branch[i]) + { + return p.error_node(); + } + else if (i < (NumberOfParameters - 1)) + { + if (!p.token_is(token_t::e_comma)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR137 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); + + return p.error_node(); + } + } + } + + if (!p.token_is(token_t::e_rbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR138 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); + + return p.error_node(); + } + else + result = p.expression_generator_.special_function(opt_type,branch); + + sd.delete_ptr = (0 == result); + + return result; + } + }; + + inline expression_node_ptr parse_special_function() + { + const std::string sf_name = current_token().value; + + // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) + if ( + !details::is_digit(sf_name[2]) || + !details::is_digit(sf_name[3]) + ) + { + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR139 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); + + return error_node(); + } + + const int id = (sf_name[2] - '0') * 10 + + (sf_name[3] - '0'); + + if (id >= details::e_sffinal) + { + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR140 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); + + return error_node(); + } + + const int sf_3_to_4 = details::e_sf48; + const details::operator_type opt_type = details::operator_type(id + 1000); + const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; + + switch (NumberOfParameters) + { + case 3 : return parse_special_function_impl::process((*this), opt_type, sf_name); + case 4 : return parse_special_function_impl::process((*this), opt_type, sf_name); + default : return error_node(); + } + } + + inline expression_node_ptr parse_null_statement() + { + next_token(); + return node_allocator_.allocate >(); + } + + #ifndef exprtk_disable_break_continue + inline expression_node_ptr parse_break_statement() + { + if (state_.parsing_break_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR141 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); + + return error_node(); + } + else if (0 == state_.parsing_loop_stmt_count) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_break_stmt); + + if (!brkcnt_list_.empty()) + { + next_token(); + + brkcnt_list_.front() = true; + + expression_node_ptr return_expr = error_node(); + + if (token_is(token_t::e_lsqrbracket)) + { + if (0 == (return_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR143 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR144 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); + + free_node(node_allocator_,return_expr); + + return error_node(); + } + } + + state_.activate_side_effect("parse_break_statement()"); + + return node_allocator_.allocate >(return_expr); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR145 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); + } + + return error_node(); + } + + inline expression_node_ptr parse_continue_statement() + { + if (0 == state_.parsing_loop_stmt_count) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR146 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); + + return error_node(); + } + else + { + next_token(); + + brkcnt_list_.front() = true; + state_.activate_side_effect("parse_continue_statement()"); + + return node_allocator_.allocate >(); + } + } + #endif + + inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) + { + expression_node_ptr size_expr = error_node(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR147 - Expected '[' as part of vector size definition", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (size_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR148 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!is_constant_node(size_expr)) + { + free_node(node_allocator_,size_expr); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR149 - Expected a literal number as size of vector '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + + const T vector_size = size_expr->value(); + + free_node(node_allocator_,size_expr); + + const T max_vector_size = T(2000000000.0); + + if ( + (vector_size <= T(0)) || + std::not_equal_to() + (T(0),vector_size - details::numeric::trunc(vector_size)) || + (vector_size > max_vector_size) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR150 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + + details::to_str(details::numeric::to_int32(vector_size)), + exprtk_error_location)); + + return error_node(); + } + + std::vector vec_initilizer_list; + + scoped_vec_delete svd((*this),vec_initilizer_list); + + bool single_value_initialiser = false; + bool vec_to_vec_initialiser = false; + bool null_initialisation = false; + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR151 - Expected ']' as part of vector size definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + if (!token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR152 - Expected ':=' as part of vector definition", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket)) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR153 - Failed to parse single vector initialiser", + exprtk_error_location)); + + return error_node(); + } + + vec_initilizer_list.push_back(initialiser); + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR154 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); + + return error_node(); + } + + single_value_initialiser = true; + } + else if (!token_is(token_t::e_lcrlbracket)) + { + expression_node_ptr initialiser = error_node(); + + // Is this a vector to vector assignment and initialisation? + if (token_t::e_symbol == current_token().type) + { + // Is it a locally defined vector? + const scope_element& se = sem_.get_active_element(current_token().value); + + if (scope_element::e_vector == se.type) + { + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // Are we dealing with a user defined vector? + else if (symtab_store_.is_vector(current_token().value)) + { + lodge_symbol(current_token().value, e_st_vector); + + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // Are we dealing with a null initialisation vector definition? + else if (token_is(token_t::e_symbol,"null")) + null_initialisation = true; + } + + if (!null_initialisation) + { + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR155 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); + + return error_node(); + } + else + vec_to_vec_initialiser = true; + } + } + else if (!token_is(token_t::e_rcrlbracket)) + { + for ( ; ; ) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR156 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); + + return error_node(); + } + else + vec_initilizer_list.push_back(initialiser); + + if (token_is(token_t::e_rcrlbracket)) + break; + + const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + + if (!token_is(token_t::e_comma) && is_next_close) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR157 - Expected ',' between vector initialisers", + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_rcrlbracket)) + break; + } + } + + if ( + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR158 - Expected ';' at end of vector definition", + exprtk_error_location)); + + return error_node(); + } + } + + if (vec_initilizer_list.size() > vector_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR159 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); + + const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); + + scope_element& se = sem_.get_element(vec_name); + + if (se.name == vec_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR160 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR161 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + vec_holder = nse.vec_node; + + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name, e_st_local_vector); + + expression_node_ptr result = error_node(); + + if (null_initialisation) + result = expression_generator_(T(0.0)); + else if (vec_to_vec_initialiser) + { + expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); + + result = expression_generator_( + details::e_assign, + vec_node, + vec_initilizer_list[0]); + } + else + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list, + single_value_initialiser); + + svd.delete_ptr = (0 == result); + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) + { + stringvar_node_t* str_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(str_name); + + if (se.name == str_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR162 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + else if (scope_element::e_string == se.type) + { + str_node = se.str_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == str_node) + { + scope_element nse; + nse.name = str_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_string; + nse.depth = state_.scope_depth; + nse.data = new std::string; + nse.str_node = new stringvar_node_t(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR163 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + str_node = nse.str_node; + + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); + } + + lodge_symbol(str_name, e_st_local_string); + + state_.activate_side_effect("parse_define_string_statement()"); + + expression_node_ptr branch[2] = {0}; + + branch[0] = str_node; + branch[1] = initialisation_expression; + + return expression_generator_(details::e_assign,branch); + } + #else + inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) + { + return error_node(); + } + #endif + + inline bool local_variable_is_shadowed(const std::string& symbol) + { + const scope_element& se = sem_.get_element(symbol); + return (se.name == symbol) && se.active; + } + + inline expression_node_ptr parse_define_var_statement() + { + if (settings_.vardef_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR164 - Illegal variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!details::imatch(current_token().value,"var")) + { + return error_node(); + } + else + next_token(); + + const std::string var_name = current_token().value; + + expression_node_ptr initialisation_expression = error_node(); + + if (!token_is(token_t::e_symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR165 - Expected a symbol for variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (details::is_reserved_symbol(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR166 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR167 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + return parse_define_vector_statement(var_name); + } + else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + return parse_uninitialised_var_statement(var_name); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR169 - Failed to parse initialisation expression", + exprtk_error_location)); + + return error_node(); + } + } + + if ( + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR170 - Expected ';' after variable definition", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + } + + if ( + (0 != initialisation_expression) && + details::is_generally_string_node(initialisation_expression) + ) + { + return parse_define_string_statement(var_name,initialisation_expression); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR171 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + return error_node(); + } + else if (scope_element::e_variable == se.type) + { + var_node = se.var_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR172 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + var_node = nse.var_node; + + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + } + + state_.activate_side_effect("parse_define_var_statement()"); + + lodge_symbol(var_name, e_st_local_variable); + + expression_node_ptr branch[2] = {0}; + + branch[0] = var_node; + branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + + return expression_generator_(details::e_assign,branch); + } + + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) + { + if ( + !token_is(token_t::e_lcrlbracket) || + !token_is(token_t::e_rcrlbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR173 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR174 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR175 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (scope_element::e_variable == se.type) + { + var_node = se.var_node; + se.active = true; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.ip_index = sem_.next_ip_index(); + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR176 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", + nse.name.c_str())); + } + + lodge_symbol(var_name, e_st_local_variable); + + state_.activate_side_effect("parse_uninitialised_var_statement()"); + + return expression_generator_(T(0)); + } + + inline expression_node_ptr parse_swap_statement() + { + if (!details::imatch(current_token().value,"swap")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR177 - Expected '(' at start of swap statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr variable0 = error_node(); + expression_node_ptr variable1 = error_node(); + + bool variable0_generated = false; + bool variable1_generated = false; + + const std::string var0_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR178 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable0 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR179 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); + + return error_node(); + } + + variable0_generated = true; + } + else + { + if (symtab_store_.is_variable(var0_name)) + { + variable0 = symtab_store_.get_variable(var0_name); + } + + const scope_element& se = sem_.get_element(var0_name); + + if ( + (se.active) && + (se.name == var0_name) && + (scope_element::e_variable == se.type) + ) + { + variable0 = se.var_node; + } + + lodge_symbol(var0_name, e_st_variable); + + if (0 == variable0) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR180 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR181 - Expected ',' between parameters to swap", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + + const std::string var1_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR182 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable1 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR183 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + + variable1_generated = true; + } + else + { + if (symtab_store_.is_variable(var1_name)) + { + variable1 = symtab_store_.get_variable(var1_name); + } + + const scope_element& se = sem_.get_element(var1_name); + + if ( + (se.active) && + (se.name == var1_name) && + (scope_element::e_variable == se.type) + ) + { + variable1 = se.var_node; + } + + lodge_symbol(var1_name, e_st_variable); + + if (0 == variable1) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR184 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR185 - Expected ')' at end of swap statement", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + if (variable1_generated) + { + free_node(node_allocator_,variable1); + } + + return error_node(); + } + + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + expression_node_ptr result = error_node(); + + if ( + (0 != (v0 = dynamic_cast(variable0))) && + (0 != (v1 = dynamic_cast(variable1))) + ) + { + result = node_allocator_.allocate >(v0, v1); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + if (variable1_generated) + { + free_node(node_allocator_,variable1); + } + } + else + result = node_allocator_.allocate > + (variable0, variable1); + + state_.activate_side_effect("parse_swap_statement()"); + + return result; + } + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr parse_return_statement() + { + if (state_.parsing_return_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR186 - Return call within a return call is not allowed", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_return_stmt); + + std::vector arg_list; + + scoped_vec_delete sdd((*this),arg_list); + + if (!details::imatch(current_token().value,"return")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR187 - Expected '[' at start of return statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + arg_list.push_back(arg); + + if (token_is(token_t::e_rsqrbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR188 - Expected ',' between values during call to return", + exprtk_error_location)); + + return error_node(); + } + } + } + else if (settings_.zero_return_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR189 - Zero parameter return statement not allowed", + exprtk_error_location)); + + return error_node(); + } + + const lexer::token prev_token = current_token(); + + if (token_is(token_t::e_rsqrbracket)) + { + if (!arg_list.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR190 - Invalid ']' found during return call", + exprtk_error_location)); + + return error_node(); + } + } + + std::string ret_param_type_list; + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (0 == arg_list[i]) + return error_node(); + else if (is_ivector_node(arg_list[i])) + ret_param_type_list += 'V'; + else if (is_generally_string_node(arg_list[i])) + ret_param_type_list += 'S'; + else + ret_param_type_list += 'T'; + } + + dec_.retparam_list_.push_back(ret_param_type_list); + + expression_node_ptr result = expression_generator_.return_call(arg_list); + + sdd.delete_ptr = (0 == result); + + state_.return_stmt_present = true; + + state_.activate_side_effect("parse_return_statement()"); + + return result; + } + #else + inline expression_node_ptr parse_return_statement() + { + return error_node(); + } + #endif + + inline bool post_variable_process(const std::string& symbol) + { + if ( + peek_token_is(token_t::e_lbracket ) || + peek_token_is(token_t::e_lcrlbracket) || + peek_token_is(token_t::e_lsqrbracket) + ) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR191 - Invalid sequence of variable '"+ symbol + "' and bracket", + exprtk_error_location)); + + return false; + } + + lexer().insert_front(token_t::e_mul); + } + + return true; + } + + inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) + { + bool implied_mul = false; + + if (details::is_generally_string_node(branch)) + return true; + + const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; + + switch (token) + { + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + default : return true; + } + + if (implied_mul) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR192 - Invalid sequence of brackets", + exprtk_error_location)); + + return false; + } + else if (token_t::e_eof != current_token().type) + { + lexer().insert_front(current_token().type); + lexer().insert_front(token_t::e_mul); + next_token(); + } + } + + return true; + } + + inline expression_node_ptr parse_symtab_symbol() + { + const std::string symbol = current_token().value; + + // Are we dealing with a variable or a special constant? + expression_node_ptr variable = symtab_store_.get_variable(symbol); + + if (variable) + { + if (symtab_store_.is_constant_node(symbol)) + { + variable = expression_generator_(variable->value()); + } + + if (!post_variable_process(symbol)) + return error_node(); + + lodge_symbol(symbol, e_st_variable); + next_token(); + + return variable; + } + + // Are we dealing with a locally defined variable, vector or string? + if (!sem_.empty()) + { + scope_element& se = sem_.get_active_element(symbol); + + if (se.active && details::imatch(se.name, symbol)) + { + if (scope_element::e_variable == se.type) + { + se.active = true; + lodge_symbol(symbol, e_st_local_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return se.var_node; + } + else if (scope_element::e_vector == se.type) + { + return parse_vector(); + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + return parse_string(); + } + #endif + } + } + + #ifndef exprtk_disable_string_capabilities + // Are we dealing with a string variable? + if (symtab_store_.is_stringvar(symbol)) + { + return parse_string(); + } + #endif + + { + // Are we dealing with a function? + ifunction* function = symtab_store_.get_function(symbol); + + if (function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr func_node = + parse_function_invocation(function,symbol); + + if (func_node) + return func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR193 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg function? + ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); + + if (vararg_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr vararg_func_node = + parse_vararg_function_call(vararg_function, symbol); + + if (vararg_func_node) + return vararg_func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR194 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg generic function? + igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); + + if (generic_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr genericfunc_node = + parse_generic_function_call(generic_function, symbol); + + if (genericfunc_node) + return genericfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR195 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + #ifndef exprtk_disable_string_capabilities + { + // Are we dealing with a vararg string returning function? + igeneric_function* string_function = symtab_store_.get_string_function(symbol); + + if (string_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr stringfunc_node = + parse_string_function_call(string_function, symbol); + + if (stringfunc_node) + return stringfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR196 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg overloaded scalar/string returning function? + igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); + + if (overload_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr overloadfunc_node = + parse_overload_function_call(overload_function, symbol); + + if (overloadfunc_node) + return overloadfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR197 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + #endif + + // Are we dealing with a vector? + if (symtab_store_.is_vector(symbol)) + { + lodge_symbol(symbol, e_st_vector); + return parse_vector(); + } + + if (details::is_reserved_symbol(symbol)) + { + if ( + settings_.function_enabled(symbol) || + !details::is_base_function(symbol) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR198 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + + // Should we handle unknown symbols? + if (resolve_unknown_symbol_ && unknown_symbol_resolver_) + { + if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) + { + symbol_table_t& symtab = symtab_store_.get_symbol_table(); + + std::string error_message; + + if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) + { + T default_value = T(0); + + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; + + if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) + { + bool create_result = false; + + switch (usr_symbol_type) + { + case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); + break; + + case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); + break; + + default : create_result = false; + } + + if (create_result) + { + expression_node_ptr var = symtab_store_.get_variable(symbol); + + if (var) + { + if (symtab_store_.is_constant_node(symbol)) + { + var = expression_generator_(var->value()); + } + + lodge_symbol(symbol, e_st_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return var; + } + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR199 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); + + } + else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) + { + if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) + { + expression_node_ptr result = parse_symtab_symbol(); + + if (result) + { + return result; + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR200 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); + } + + return error_node(); + } + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR201 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + + inline expression_node_ptr parse_symbol() + { + static const std::string symbol_if = "if" ; + static const std::string symbol_while = "while" ; + static const std::string symbol_repeat = "repeat" ; + static const std::string symbol_for = "for" ; + static const std::string symbol_switch = "switch" ; + static const std::string symbol_null = "null" ; + static const std::string symbol_break = "break" ; + static const std::string symbol_continue = "continue"; + static const std::string symbol_var = "var" ; + static const std::string symbol_swap = "swap" ; + static const std::string symbol_return = "return" ; + static const std::string symbol_not = "not" ; + + const std::string symbol = current_token().value; + + if (valid_vararg_operation(symbol)) + { + return parse_vararg_function(); + } + else if (details::imatch(symbol, symbol_not)) + { + return parse_not_statement(); + } + else if (valid_base_operation(symbol)) + { + return parse_base_operation(); + } + else if ( + details::imatch(symbol, symbol_if) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_conditional_statement(); + } + else if ( + details::imatch(symbol, symbol_while) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_while_loop(); + } + else if ( + details::imatch(symbol, symbol_repeat) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_repeat_until_loop(); + } + else if ( + details::imatch(symbol, symbol_for) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_for_loop(); + } + else if ( + details::imatch(symbol, symbol_switch) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_switch_statement(); + } + else if (details::is_valid_sf_symbol(symbol)) + { + return parse_special_function(); + } + else if (details::imatch(symbol, symbol_null)) + { + return parse_null_statement(); + } + #ifndef exprtk_disable_break_continue + else if (details::imatch(symbol, symbol_break)) + { + return parse_break_statement(); + } + else if (details::imatch(symbol, symbol_continue)) + { + return parse_continue_statement(); + } + #endif + else if (details::imatch(symbol, symbol_var)) + { + return parse_define_var_statement(); + } + else if (details::imatch(symbol, symbol_swap)) + { + return parse_swap_statement(); + } + #ifndef exprtk_disable_return_statement + else if ( + details::imatch(symbol, symbol_return) && + settings_.control_struct_enabled(symbol) + ) + { + return parse_return_statement(); + } + #endif + else if (symtab_store_.valid() || !sem_.empty()) + { + return parse_symtab_symbol(); + } + else + { + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR202 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, + exprtk_error_location)); + + return error_node(); + } + } + + inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) + { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + + expression_node_ptr branch = error_node(); + + if (token_t::e_number == current_token().type) + { + T numeric_value = T(0); + + if (details::string_to_real(current_token().value, numeric_value)) + { + expression_node_ptr literal_exp = expression_generator_(numeric_value); + + if (0 == literal_exp) + { + set_error( + make_error(parser_error::e_numeric, + current_token(), + "ERR203 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + branch = literal_exp; + } + else + { + set_error( + make_error(parser_error::e_numeric, + current_token(), + "ERR204 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); + + return error_node(); + } + } + else if (token_t::e_symbol == current_token().type) + { + branch = parse_symbol(); + } + #ifndef exprtk_disable_string_capabilities + else if (token_t::e_string == current_token().type) + { + branch = parse_const_string(); + } + #endif + else if (token_t::e_lbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR205 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + details::free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lbracket,branch)) + { + details::free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_lsqrbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR206 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + details::free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) + { + details::free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_lcrlbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR207 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + details::free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) + { + details::free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_sub == current_token().type) + { + next_token(); + branch = parse_expression(e_level11); + + if ( + branch && + !( + details::is_neg_unary_node (branch) && + simplify_unary_negation_branch(branch) + ) + ) + { + expression_node_ptr result = expression_generator_(details::e_neg,branch); + + if (0 == result) + { + details::free_node(node_allocator_,branch); + + return error_node(); + } + else + branch = result; + } + } + else if (token_t::e_add == current_token().type) + { + next_token(); + branch = parse_expression(e_level13); + } + else if (token_t::e_eof == current_token().type) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR208 - Premature end of expression[1]", + exprtk_error_location)); + + return error_node(); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR209 - Premature end of expression[2]", + exprtk_error_location)); + + return error_node(); + } + + if ( + branch && + (e_level00 == precedence) && + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) + ) + { + branch = parse_ternary_conditional_statement(branch); + } + + parse_pending_string_rangesize(branch); + + return branch; + } + + template + class expression_generator + { + public: + + typedef details::expression_node* expression_node_ptr; + typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); + typedef std::map synthesize_map_t; + typedef typename exprtk::parser parser_t; + typedef const Type& vtype; + typedef const Type ctype; + + inline void init_synthesize_map() + { + #ifndef exprtk_disable_enhanced_features + synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; + synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; + synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; + + #define register_synthezier(S) \ + synthesize_map_[S ::node_type::id()] = S ::process; \ + + register_synthezier(synthesize_vovov_expression0) + register_synthezier(synthesize_vovov_expression1) + register_synthezier(synthesize_vovoc_expression0) + register_synthezier(synthesize_vovoc_expression1) + register_synthezier(synthesize_vocov_expression0) + register_synthezier(synthesize_vocov_expression1) + register_synthezier(synthesize_covov_expression0) + register_synthezier(synthesize_covov_expression1) + register_synthezier(synthesize_covoc_expression0) + register_synthezier(synthesize_covoc_expression1) + register_synthezier(synthesize_cocov_expression1) + register_synthezier(synthesize_vococ_expression0) + + register_synthezier(synthesize_vovovov_expression0) + register_synthezier(synthesize_vovovoc_expression0) + register_synthezier(synthesize_vovocov_expression0) + register_synthezier(synthesize_vocovov_expression0) + register_synthezier(synthesize_covovov_expression0) + register_synthezier(synthesize_covocov_expression0) + register_synthezier(synthesize_vocovoc_expression0) + register_synthezier(synthesize_covovoc_expression0) + register_synthezier(synthesize_vococov_expression0) + + register_synthezier(synthesize_vovovov_expression1) + register_synthezier(synthesize_vovovoc_expression1) + register_synthezier(synthesize_vovocov_expression1) + register_synthezier(synthesize_vocovov_expression1) + register_synthezier(synthesize_covovov_expression1) + register_synthezier(synthesize_covocov_expression1) + register_synthezier(synthesize_vocovoc_expression1) + register_synthezier(synthesize_covovoc_expression1) + register_synthezier(synthesize_vococov_expression1) + + register_synthezier(synthesize_vovovov_expression2) + register_synthezier(synthesize_vovovoc_expression2) + register_synthezier(synthesize_vovocov_expression2) + register_synthezier(synthesize_vocovov_expression2) + register_synthezier(synthesize_covovov_expression2) + register_synthezier(synthesize_covocov_expression2) + register_synthezier(synthesize_vocovoc_expression2) + register_synthezier(synthesize_covovoc_expression2) + + register_synthezier(synthesize_vovovov_expression3) + register_synthezier(synthesize_vovovoc_expression3) + register_synthezier(synthesize_vovocov_expression3) + register_synthezier(synthesize_vocovov_expression3) + register_synthezier(synthesize_covovov_expression3) + register_synthezier(synthesize_covocov_expression3) + register_synthezier(synthesize_vocovoc_expression3) + register_synthezier(synthesize_covovoc_expression3) + register_synthezier(synthesize_vococov_expression3) + + register_synthezier(synthesize_vovovov_expression4) + register_synthezier(synthesize_vovovoc_expression4) + register_synthezier(synthesize_vovocov_expression4) + register_synthezier(synthesize_vocovov_expression4) + register_synthezier(synthesize_covovov_expression4) + register_synthezier(synthesize_covocov_expression4) + register_synthezier(synthesize_vocovoc_expression4) + register_synthezier(synthesize_covovoc_expression4) + #endif + } + + inline void set_parser(parser_t& p) + { + parser_ = &p; + } + + inline void set_uom(unary_op_map_t& unary_op_map) + { + unary_op_map_ = &unary_op_map; + } + + inline void set_bom(binary_op_map_t& binary_op_map) + { + binary_op_map_ = &binary_op_map; + } + + inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) + { + inv_binary_op_map_ = &inv_binary_op_map; + } + + inline void set_sf3m(sf3_map_t& sf3_map) + { + sf3_map_ = &sf3_map; + } + + inline void set_sf4m(sf4_map_t& sf4_map) + { + sf4_map_ = &sf4_map; + } + + inline void set_allocator(details::node_allocator& na) + { + node_allocator_ = &na; + } + + inline void set_strength_reduction_state(const bool enabled) + { + strength_reduction_enabled_ = enabled; + } + + inline bool strength_reduction_enabled() const + { + return strength_reduction_enabled_; + } + + inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) + { + typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); + + if ((*binary_op_map_).end() == bop_itr) + return false; + + bop = bop_itr->second; + + return true; + } + + inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) + { + typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); + + if ((*unary_op_map_).end() == uop_itr) + return false; + + uop = uop_itr->second; + + return true; + } + + inline details::operator_type get_operator(const binary_functor_t& bop) const + { + return (*inv_binary_op_map_).find(bop)->second; + } + + inline expression_node_ptr operator() (const Type& v) const + { + return node_allocator_->allocate(v); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr operator() (const std::string& s) const + { + return node_allocator_->allocate(s); + } + + inline expression_node_ptr operator() (std::string& s, range_t& rp) const + { + return node_allocator_->allocate_rr(s,rp); + } + + inline expression_node_ptr operator() (const std::string& s, range_t& rp) const + { + return node_allocator_->allocate_tt(s,rp); + } + + inline expression_node_ptr operator() (expression_node_ptr branch, range_t& rp) const + { + if (is_generally_string_node(branch)) + return node_allocator_->allocate_tt(branch,rp); + else + return error_node(); + } + #endif + + inline bool unary_optimisable(const details::operator_type& operation) const + { + return (details::e_abs == operation) || (details::e_acos == operation) || + (details::e_acosh == operation) || (details::e_asin == operation) || + (details::e_asinh == operation) || (details::e_atan == operation) || + (details::e_atanh == operation) || (details::e_ceil == operation) || + (details::e_cos == operation) || (details::e_cosh == operation) || + (details::e_exp == operation) || (details::e_expm1 == operation) || + (details::e_floor == operation) || (details::e_log == operation) || + (details::e_log10 == operation) || (details::e_log2 == operation) || + (details::e_log1p == operation) || (details::e_neg == operation) || + (details::e_pos == operation) || (details::e_round == operation) || + (details::e_sin == operation) || (details::e_sinc == operation) || + (details::e_sinh == operation) || (details::e_sqrt == operation) || + (details::e_tan == operation) || (details::e_tanh == operation) || + (details::e_cot == operation) || (details::e_sec == operation) || + (details::e_csc == operation) || (details::e_r2d == operation) || + (details::e_d2r == operation) || (details::e_d2g == operation) || + (details::e_g2d == operation) || (details::e_notl == operation) || + (details::e_sgn == operation) || (details::e_erf == operation) || + (details::e_erfc == operation) || (details::e_ncdf == operation) || + (details::e_frac == operation) || (details::e_trunc == operation) ; + } + + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const + { + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + + if (sf3_map_->end() == itr) + return false; + else + tfunc = itr->second.first; + + return true; + } + + inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const + { + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + + if (sf4_map_->end() == itr) + return false; + else + qfunc = itr->second.first; + + return true; + } + + inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const + { + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + + if (sf3_map_->end() == itr) + return false; + else + operation = itr->second.second; + + return true; + } + + inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const + { + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + + if (sf4_map_->end() == itr) + return false; + else + operation = itr->second.second; + + return true; + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[1]) + { + if (0 == branch[0]) + { + return error_node(); + } + else if (details::is_null_node(branch[0])) + { + return branch[0]; + } + else if (details::is_break_node(branch[0])) + { + return error_node(); + } + else if (details::is_continue_node(branch[0])) + { + return error_node(); + } + else if (details::is_constant_node(branch[0])) + { + return synthesize_expression(operation,branch); + } + else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) + { + return synthesize_uv_expression(operation,branch); + } + else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) + { + return synthesize_uvec_expression(operation,branch); + } + else + return synthesize_unary_expression(operation,branch); + } + + inline bool is_assignment_operation(const details::operator_type& operation) const + { + return ( + (details::e_addass == operation) || + (details::e_subass == operation) || + (details::e_mulass == operation) || + (details::e_divass == operation) || + (details::e_modass == operation) + ) && + parser_->settings_.assignment_enabled(operation); + } + + #ifndef exprtk_disable_string_capabilities + inline bool valid_string_operation(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) || + (details::e_assign == operation) || + (details::e_addass == operation) || + (details::e_swap == operation) ; + } + #else + inline bool valid_string_operation(const details::operator_type&) const + { + return false; + } + #endif + + inline std::string to_str(const details::operator_type& operation) const + { + switch (operation) + { + case details::e_add : return "+" ; + case details::e_sub : return "-" ; + case details::e_mul : return "*" ; + case details::e_div : return "/" ; + case details::e_mod : return "%" ; + case details::e_pow : return "^" ; + case details::e_lt : return "<" ; + case details::e_lte : return "<=" ; + case details::e_gt : return ">" ; + case details::e_gte : return ">=" ; + case details::e_eq : return "==" ; + case details::e_ne : return "!=" ; + case details::e_and : return "and" ; + case details::e_nand : return "nand" ; + case details::e_or : return "or" ; + case details::e_nor : return "nor" ; + case details::e_xor : return "xor" ; + case details::e_xnor : return "xnor" ; + default : return "UNKNOWN"; + } + } + + inline bool operation_optimisable(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_mod == operation) || + (details::e_pow == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation) || + (details::e_xnor == operation) ; + } + + inline std::string branch_to_id(expression_node_ptr branch) const + { + static const std::string null_str ("(null)" ); + static const std::string const_str ("(c)" ); + static const std::string var_str ("(v)" ); + static const std::string vov_str ("(vov)" ); + static const std::string cov_str ("(cov)" ); + static const std::string voc_str ("(voc)" ); + static const std::string str_str ("(s)" ); + static const std::string strrng_str ("(rngs)" ); + static const std::string cs_str ("(cs)" ); + static const std::string cstrrng_str("(crngs)"); + + if (details::is_null_node(branch)) + return null_str; + else if (details::is_constant_node(branch)) + return const_str; + else if (details::is_variable_node(branch)) + return var_str; + else if (details::is_vov_node(branch)) + return vov_str; + else if (details::is_cov_node(branch)) + return cov_str; + else if (details::is_voc_node(branch)) + return voc_str; + else if (details::is_string_node(branch)) + return str_str; + else if (details::is_const_string_node(branch)) + return cs_str; + else if (details::is_string_range_node(branch)) + return strrng_str; + else if (details::is_const_string_range_node(branch)) + return cstrrng_str; + else if (details::is_t0ot1ot2_node(branch)) + return "(" + dynamic_cast*>(branch)->type_id() + ")"; + else if (details::is_t0ot1ot2ot3_node(branch)) + return "(" + dynamic_cast*>(branch)->type_id() + ")"; + else + return "ERROR"; + } + + inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const + { + return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); + } + + inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_constant_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + details::is_constant_node(branch[1]) ; + } + + inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_constant_node(branch[0]) && + !details::is_constant_node(branch[1]) ; + } + + inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_constant_node(branch[0]) && + details::is_constant_node(branch[1]) ; + } + + inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])) ; + } + else + return false; + } + + inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])) ; + } + else + return false; + } + + inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_uv_node(branch[0]) && + details::is_uv_node(branch[1]) ; + } + + inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + !details::is_variable_node(branch[1]) ; + } + + inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_constant_node(branch[0]) || + !details::is_constant_node(branch[1]) ; + } + + inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (is_assignment_operation(operation)) + { + const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + + if (details::is_string_node(branch[0])) + return !b1_is_genstring; + else + return ( + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node (branch[0]) && + !details::is_rebasevector_elem_node (branch[0]) && + !details::is_rebasevector_celem_node(branch[0]) && + !details::is_vector_node (branch[0]) + ) + || b1_is_genstring; + } + else + return false; + } + + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const + { + if ( + !details::is_constant_node(branch[1]) || + details::is_constant_node(branch[0]) || + details::is_variable_node(branch[0]) || + details::is_vector_node (branch[0]) || + details::is_generally_string_node(branch[0]) + ) + return false; + + const Type c = static_cast*>(branch[1])->value(); + + return cardinal_pow_optimisable(operation, c); + } + + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const + { + return ( + details::is_break_node (branch[0]) || + details::is_break_node (branch[1]) || + details::is_continue_node(branch[0]) || + details::is_continue_node(branch[1]) + ); + } + + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + + bool result = false; + + if (b0_string != b1_string) + result = true; + else if (!valid_string_operation(operation) && b0_string && b1_string) + result = true; + + if (result) + { + parser_->set_synthesis_error("Invalid string operation"); + } + + return result; + } + + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + const bool b2_string = is_generally_string_node(branch[2]); + + bool result = false; + + if ((b0_string != b1_string) || (b1_string != b2_string)) + result = true; + else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) + result = true; + + if (result) + { + parser_->set_synthesis_error("Invalid string operation"); + } + + return result; + } + + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + + return (b0_string && b1_string && valid_string_operation(operation)); + } + + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + const bool b2_string = is_generally_string_node(branch[2]); + + return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); + } + + #ifndef exprtk_disable_sc_andor + inline bool is_shortcircuit_expression(const details::operator_type& operation) const + { + return ( + (details::e_scand == operation) || + (details::e_scor == operation) + ); + } + #else + inline bool is_shortcircuit_expression(const details::operator_type&) const + { + return false; + } + #endif + + inline bool is_null_present(expression_node_ptr (&branch)[2]) const + { + return ( + details::is_null_node(branch[0]) || + details::is_null_node(branch[1]) + ); + } + + inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) + return false; + else + return ( + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_equal == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation) || + (details::e_xnor == operation) + ); + } + + inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) + return false; + else + return ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_pow == operation) + ); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + { + return error_node(); + } + else if (is_invalid_string_op(operation,branch)) + { + return error_node(); + } + else if (is_invalid_assignment_op(operation,branch)) + { + return error_node(); + } + else if (is_invalid_break_continue_op(branch)) + { + return error_node(); + } + else if (details::e_assign == operation) + { + return synthesize_assignment_expression(operation, branch); + } + else if (details::e_swap == operation) + { + return synthesize_swap_expression(branch); + } + else if (is_assignment_operation(operation)) + { + return synthesize_assignment_operation_expression(operation, branch); + } + else if (is_vector_eqineq_logic_operation(operation, branch)) + { + return synthesize_veceqineqlogic_operation_expression(operation, branch); + } + else if (is_vector_arithmetic_operation(operation, branch)) + { + return synthesize_vecarithmetic_operation_expression(operation, branch); + } + else if (is_shortcircuit_expression(operation)) + { + return synthesize_shortcircuit_expression(operation, branch); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } + else if (is_null_present(branch)) + { + return synthesize_null_expression(operation, branch); + } + #ifndef exprtk_disable_cardinal_pow_optimisation + else if (is_constpow_operation(operation, branch)) + { + return cardinal_pow_optimisation(branch); + } + #endif + + expression_node_ptr result = error_node(); + + #ifndef exprtk_disable_enhanced_features + if (synthesize_expression(operation, branch, result)) + { + return result; + } + else + #endif + + { + /* + Possible reductions: + 1. c o cob -> cob + 2. cob o c -> cob + 3. c o boc -> boc + 4. boc o c -> boc + */ + result = error_node(); + + if (cocob_optimisable(operation, branch)) + { + result = synthesize_cocob_expression::process((*this), operation, branch); + } + else if (coboc_optimisable(operation, branch) && (0 == result)) + { + result = synthesize_coboc_expression::process((*this), operation, branch); + } + + if (result) + return result; + } + + if (uvouv_optimisable(operation, branch)) + { + return synthesize_uvouv_expression(operation, branch); + } + else if (vob_optimisable(operation, branch)) + { + return synthesize_vob_expression::process((*this), operation, branch); + } + else if (bov_optimisable(operation, branch)) + { + return synthesize_bov_expression::process((*this), operation, branch); + } + else if (cob_optimisable(operation, branch)) + { + return synthesize_cob_expression::process((*this), operation, branch); + } + else if (boc_optimisable(operation, branch)) + { + return synthesize_boc_expression::process((*this), operation, branch); + } + #ifndef exprtk_disable_enhanced_features + else if (cov_optimisable(operation, branch)) + { + return synthesize_cov_expression::process((*this), operation, branch); + } + #endif + else if (binext_optimisable(operation, branch)) + { + return synthesize_binary_ext_expression::process((*this), operation, branch); + } + else + return synthesize_expression(operation, branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if ( + (0 == branch[0]) || + (0 == branch[1]) || + (0 == branch[2]) + ) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if (is_invalid_string_op(operation, branch)) + { + return error_node(); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } + else + return synthesize_expression(operation, branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + return synthesize_expression(operation,branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) + { + expression_node_ptr branch[1] = { b0 }; + return (*this)(operation,branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) + { + expression_node_ptr result = error_node(); + + if ((0 != b0) && (0 != b1)) + { + expression_node_ptr branch[2] = { b0, b1 }; + result = expression_generator::operator()(operation, branch); + b0 = branch[0]; + b1 = branch[1]; + } + + return result; + } + + inline expression_node_ptr conditional(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_->allocate >(); + } + } + else if ((0 != consequent) && (0 != alternative)) + { + return node_allocator_-> + allocate(condition, consequent, alternative); + } + else + return node_allocator_-> + allocate(condition, consequent); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr conditional_string(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_-> + allocate_c >(""); + } + } + else if ((0 != consequent) && (0 != alternative)) + return node_allocator_-> + allocate(condition, consequent, alternative); + else + return error_node(); + } + #else + inline expression_node_ptr conditional_string(expression_node_ptr, + expression_node_ptr, + expression_node_ptr) const + { + return error_node(); + } + #endif + + inline expression_node_ptr conditional_vector(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_->allocate >(); + + } + } + else if ((0 != consequent) && (0 != alternative)) + { + return node_allocator_-> + allocate(condition, consequent, alternative); + } + else + return error_node(); + } + + inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const + { + if ( + parser_->loop_runtime_check_ && + (loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) + ) + { + return parser_->loop_runtime_check_; + } + + return loop_runtime_check_ptr(0); + } + + inline expression_node_ptr while_loop(expression_node_ptr& condition, + expression_node_ptr& branch, + const bool break_continue_present = false) const + { + if (!break_continue_present && details::is_constant_node(condition)) + { + expression_node_ptr result = error_node(); + if (details::is_true(condition)) + // Infinite loops are not allowed. + result = error_node(); + else + result = node_allocator_->allocate >(); + + details::free_node(*node_allocator_, condition); + details::free_node(*node_allocator_, branch ); + + return result; + } + else if (details::is_null_node(condition)) + { + details::free_node(*node_allocator_,condition); + + return branch; + } + + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_while_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate + (condition, branch, rtc); + else + return node_allocator_->allocate + (condition, branch); + } + #ifndef exprtk_disable_break_continue + else + { + if (rtc) + return node_allocator_->allocate + (condition, branch, rtc); + else + return node_allocator_->allocate + (condition, branch); + } + #else + return error_node(); + #endif + } + + inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, + expression_node_ptr& branch, + const bool break_continue_present = false) const + { + if (!break_continue_present && details::is_constant_node(condition)) + { + if ( + details::is_true(condition) && + details::is_constant_node(branch) + ) + { + free_node(*node_allocator_,condition); + + return branch; + } + + details::free_node(*node_allocator_, condition); + details::free_node(*node_allocator_, branch ); + + return error_node(); + } + else if (details::is_null_node(condition)) + { + details::free_node(*node_allocator_,condition); + + return branch; + } + + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate + (condition, branch, rtc); + else + return node_allocator_->allocate + (condition, branch); + } + #ifndef exprtk_disable_break_continue + else + { + if (rtc) + return node_allocator_->allocate + (condition, branch, rtc); + else + return node_allocator_->allocate + (condition, branch); + } + #else + return error_node(); + #endif + } + + inline expression_node_ptr for_loop(expression_node_ptr& initialiser, + expression_node_ptr& condition, + expression_node_ptr& incrementor, + expression_node_ptr& loop_body, + bool break_continue_present = false) const + { + if (!break_continue_present && details::is_constant_node(condition)) + { + expression_node_ptr result = error_node(); + + if (details::is_true(condition)) + // Infinite loops are not allowed. + result = error_node(); + else + result = node_allocator_->allocate >(); + + details::free_node(*node_allocator_, initialiser); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, incrementor); + details::free_node(*node_allocator_, loop_body ); + + return result; + } + else if (details::is_null_node(condition) || (0 == condition)) + { + details::free_node(*node_allocator_, initialiser); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, incrementor); + + return loop_body; + } + + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_for_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body, + rtc + ); + else + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body + ); + } + #ifndef exprtk_disable_break_continue + else + { + if (rtc) + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body, + rtc + ); + else + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body + ); + } + #else + return error_node(); + #endif + } + + template class Sequence> + inline expression_node_ptr const_optimise_switch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if ((0 == result) && details::is_true(condition)) + { + result = consequent; + break; + } + } + + if (0 == result) + { + result = arg_list.back(); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + template class Sequence> + inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if (details::is_true(condition)) + { + result = consequent; + } + } + + if (0 == result) + { + T zero = T(0); + result = node_allocator_->allocate(zero); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr& current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + details::free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + struct switch_nodes + { + typedef std::vector > arg_list_t; + + #define case_stmt(N) \ + if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ + + struct switch_impl_1 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) + + assert(arg.size() == ((2 * 1) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_2 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + + assert(arg.size() == ((2 * 2) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_3 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) + + assert(arg.size() == ((2 * 3) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_4 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + + assert(arg.size() == ((2 * 4) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_5 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) + + assert(arg.size() == ((2 * 5) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_6 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + + assert(arg.size() == ((2 * 6) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_7 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + case_stmt(6) + + assert(arg.size() == ((2 * 7) + 1)); + + return arg.back().first->value(); + } + }; + + #undef case_stmt + }; + + template class Sequence> + inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) + { + if (arg_list.empty()) + return error_node(); + else if ( + !all_nodes_valid(arg_list) || + (!default_statement_present && (arg_list.size() < 2)) + ) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_switch(arg_list); + + switch ((arg_list.size() - 1) / 2) + { + #define case_stmt(N) \ + case N : \ + return node_allocator_-> \ + allocate >(arg_list); \ + + case_stmt(1) + case_stmt(2) + case_stmt(3) + case_stmt(4) + case_stmt(5) + case_stmt(6) + case_stmt(7) + #undef case_stmt + + default : return node_allocator_->allocate >(arg_list); + } + } + + template class Sequence> + inline expression_node_ptr multi_switch_statement(Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_mswitch(arg_list); + else + return node_allocator_->allocate >(arg_list); + } + + #define unary_opr_switch_statements \ + case_stmt(details::e_abs , details::abs_op ) \ + case_stmt(details::e_acos , details::acos_op ) \ + case_stmt(details::e_acosh , details::acosh_op) \ + case_stmt(details::e_asin , details::asin_op ) \ + case_stmt(details::e_asinh , details::asinh_op) \ + case_stmt(details::e_atan , details::atan_op ) \ + case_stmt(details::e_atanh , details::atanh_op) \ + case_stmt(details::e_ceil , details::ceil_op ) \ + case_stmt(details::e_cos , details::cos_op ) \ + case_stmt(details::e_cosh , details::cosh_op ) \ + case_stmt(details::e_exp , details::exp_op ) \ + case_stmt(details::e_expm1 , details::expm1_op) \ + case_stmt(details::e_floor , details::floor_op) \ + case_stmt(details::e_log , details::log_op ) \ + case_stmt(details::e_log10 , details::log10_op) \ + case_stmt(details::e_log2 , details::log2_op ) \ + case_stmt(details::e_log1p , details::log1p_op) \ + case_stmt(details::e_neg , details::neg_op ) \ + case_stmt(details::e_pos , details::pos_op ) \ + case_stmt(details::e_round , details::round_op) \ + case_stmt(details::e_sin , details::sin_op ) \ + case_stmt(details::e_sinc , details::sinc_op ) \ + case_stmt(details::e_sinh , details::sinh_op ) \ + case_stmt(details::e_sqrt , details::sqrt_op ) \ + case_stmt(details::e_tan , details::tan_op ) \ + case_stmt(details::e_tanh , details::tanh_op ) \ + case_stmt(details::e_cot , details::cot_op ) \ + case_stmt(details::e_sec , details::sec_op ) \ + case_stmt(details::e_csc , details::csc_op ) \ + case_stmt(details::e_r2d , details::r2d_op ) \ + case_stmt(details::e_d2r , details::d2r_op ) \ + case_stmt(details::e_d2g , details::d2g_op ) \ + case_stmt(details::e_g2d , details::g2d_op ) \ + case_stmt(details::e_notl , details::notl_op ) \ + case_stmt(details::e_sgn , details::sgn_op ) \ + case_stmt(details::e_erf , details::erf_op ) \ + case_stmt(details::e_erfc , details::erfc_op ) \ + case_stmt(details::e_ncdf , details::ncdf_op ) \ + case_stmt(details::e_frac , details::frac_op ) \ + case_stmt(details::e_trunc , details::trunc_op) \ + + inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + T& v = static_cast*>(branch[0])->ref(); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(v); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > > \ + (operation, branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, + expression_node_ptr (&branch)[3]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrr > > \ + (v0, v1, v2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf3(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf3(operation,branch); + else + { + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + } + + inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + const Type& v3 = static_cast(branch[3])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrrr > > \ + (v0, v1, v2, v3); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf4(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf4(operation,branch); + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : temp_node = node_allocator_-> \ + allocate > > \ + (arg_list); \ + break; \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline bool special_one_parameter_vararg(const details::operator_type& operation) const + { + return ( + (details::e_sum == operation) || + (details::e_prod == operation) || + (details::e_avg == operation) || + (details::e_min == operation) || + (details::e_max == operation) + ); + } + + template class Sequence> + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + { + if (1 == arg_list.size()) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list[0]); \ + + case_stmt(details::e_sum , details::vec_add_op) + case_stmt(details::e_prod , details::vec_mul_op) + case_stmt(details::e_avg , details::vec_avg_op) + case_stmt(details::e_min , details::vec_min_op) + case_stmt(details::e_max , details::vec_max_op) + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + } + + template class Sequence> + inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_varargfunc(operation,arg_list); + else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) + return vectorize_func(operation,arg_list); + else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + return arg_list[0]; + else if (all_nodes_variables(arg_list)) + return varnode_optimise_varargfunc(operation,arg_list); + + #ifndef exprtk_disable_string_capabilities + if (details::e_smulti == operation) + { + return node_allocator_-> + allocate > >(arg_list); + } + else + #endif + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + } + + template + inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) + { + typedef typename details::function_N_node function_N_node_t; + expression_node_ptr result = synthesize_expression(f,b); + + if (0 == result) + return error_node(); + else + { + // Can the function call be completely optimised? + if (details::is_constant_node(result)) + return result; + else if (!all_nodes_valid(b)) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + else if (N != f->param_count) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + + function_N_node_t* func_node_ptr = reinterpret_cast(result); + + if (!func_node_ptr->init_branches(b)) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + + return result; + } + } + + inline expression_node_ptr function(ifunction_t* f) + { + typedef typename details::function_N_node function_N_node_t; + return node_allocator_->allocate(f); + } + + inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, + std::vector& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + + typedef details::vararg_function_node alloc_type; + + expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); + + if ( + !arg_list.empty() && + !vaf->has_side_effects() && + is_constant_foldable(arg_list) + ) + { + const Type v = result->value(); + details::free_node(*node_allocator_,result); + result = node_allocator_->allocate(v); + } + + parser_->state_.activate_side_effect("vararg_function_call()"); + + return result; + } + + inline expression_node_ptr generic_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::generic_function_node alloc_type1; + typedef details::multimode_genfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(arg_list,gf); + else + result = node_allocator_->allocate(gf, param_seq_index, arg_list); + + alloc_type1* genfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + parser_->state_.type_check_enabled && + is_constant_foldable(arg_list) + ) + { + genfunc_node_ptr->init_branches(); + + const Type v = result->value(); + + details::free_node(*node_allocator_,result); + + return node_allocator_->allocate(v); + } + else if (genfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("generic_function_call()"); + + return result; + } + else + { + details::free_node(*node_allocator_, result); + details::free_all_nodes(*node_allocator_, arg_list); + + return error_node(); + } + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr string_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::string_function_node alloc_type1; + typedef details::multimode_strfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(gf,arg_list); + else + result = node_allocator_->allocate(gf, param_seq_index, arg_list); + + alloc_type1* strfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + is_constant_foldable(arg_list) + ) + { + strfunc_node_ptr->init_branches(); + + const Type v = result->value(); + + details::free_node(*node_allocator_,result); + + return node_allocator_->allocate(v); + } + else if (strfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("string_function_call()"); + + return result; + } + else + { + details::free_node (*node_allocator_,result ); + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + } + #endif + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr return_call(std::vector& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::return_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_rr(arg_list,parser_->results_ctx()); + + alloc_type* return_node_ptr = static_cast(result); + + if (return_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("return_call()"); + + return result; + } + else + { + details::free_node (*node_allocator_, result ); + details::free_all_nodes(*node_allocator_, arg_list); + + return error_node(); + } + } + + inline expression_node_ptr return_envelope(expression_node_ptr body, + results_context_t* rc, + bool*& return_invoked) + { + typedef details::return_envelope_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_cr(body,(*rc)); + + return_invoked = static_cast(result)->retinvk_ptr(); + + return result; + } + #else + inline expression_node_ptr return_call(std::vector&) + { + return error_node(); + } + + inline expression_node_ptr return_envelope(expression_node_ptr, + results_context_t*, + bool*&) + { + return error_node(); + } + #endif + + inline expression_node_ptr vector_element(const std::string& symbol, + vector_holder_ptr vector_base, + expression_node_ptr index) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(index)) + { + std::size_t i = static_cast(details::numeric::to_int64(index->value())); + + details::free_node(*node_allocator_,index); + + if (vector_base->rebaseable()) + { + return node_allocator_->allocate(i,vector_base); + } + + const scope_element& se = parser_->sem_.get_element(symbol,i); + + if (se.index == i) + { + result = se.var_node; + } + else + { + scope_element nse; + nse.name = symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vecelem; + nse.index = i; + nse.depth = parser_->state_.scope_depth; + nse.data = 0; + nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); + + if (!parser_->sem_.add_element(nse)) + { + parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); + + parser_->sem_.free_element(nse); + + result = error_node(); + } + + exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + + parser_->state_.activate_side_effect("vector_element()"); + + result = nse.var_node; + } + } + else if (vector_base->rebaseable()) + result = node_allocator_->allocate(index,vector_base); + else + result = node_allocator_->allocate(index,vector_base); + + return result; + } + + private: + + template + inline bool is_constant_foldable(NodePtr (&b)[N]) const + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + template class Sequence> + inline bool is_constant_foldable(const Sequence& b) const + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + void lodge_assignment(symbol_type cst, expression_node_ptr node) + { + parser_->state_.activate_side_effect("lodge_assignment()"); + + if (!parser_->dec_.collect_assignments()) + return; + + std::string symbol_name; + + switch (cst) + { + case e_st_variable : symbol_name = parser_->symtab_store_ + .get_variable_name(node); + break; + + #ifndef exprtk_disable_string_capabilities + case e_st_string : symbol_name = parser_->symtab_store_ + .get_stringvar_name(node); + break; + #endif + + case e_st_vector : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + } + break; + + case e_st_vecelem : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + + cst = e_st_vector; + } + break; + + default : return; + } + + if (!symbol_name.empty()) + { + parser_->dec_.add_assignment(symbol_name,cst); + } + } + + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + return synthesize_expression(operation,branch); + } + else if (details::is_vector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + #ifndef exprtk_disable_string_capabilities + else if (details::is_string_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_string_range_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation, branch); + } + #endif + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + return synthesize_expression(operation, branch); + else + return synthesize_expression(operation, branch); + } + else + { + parser_->set_synthesis_error("Invalid assignment operation.[1]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + } + #ifndef exprtk_disable_string_capabilities + else if ( + (details::e_addass == operation) && + details::is_string_node(branch[0]) + ) + { + typedef details::assignment_string_node addass_t; + + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation,branch); + } + #endif + else + { + parser_->set_synthesis_error("Invalid assignment operation[2]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define batch_eqineq_logic_case \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_equal , details::equal_op) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op ) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op ) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef batch_eqineq_logic_case + } + + inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define vector_ops \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef vector_ops + } + + inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) + { + const bool v0_is_ivar = details::is_ivariable_node(branch[0]); + const bool v1_is_ivar = details::is_ivariable_node(branch[1]); + + const bool v0_is_ivec = details::is_ivector_node (branch[0]); + const bool v1_is_ivec = details::is_ivector_node (branch[1]); + + #ifndef exprtk_disable_string_capabilities + const bool v0_is_str = details::is_generally_string_node(branch[0]); + const bool v1_is_str = details::is_generally_string_node(branch[1]); + #endif + + expression_node_ptr result = error_node(); + + if (v0_is_ivar && v1_is_ivar) + { + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + if ( + (0 != (v0 = dynamic_cast(branch[0]))) && + (0 != (v1 = dynamic_cast(branch[1]))) + ) + { + result = node_allocator_->allocate >(v0,v1); + } + else + result = node_allocator_->allocate >(branch[0],branch[1]); + } + else if (v0_is_ivec && v1_is_ivec) + { + result = node_allocator_->allocate >(branch[0],branch[1]); + } + #ifndef exprtk_disable_string_capabilities + else if (v0_is_str && v1_is_str) + { + if (is_string_node(branch[0]) && is_string_node(branch[1])) + result = node_allocator_->allocate > + (branch[0], branch[1]); + else + result = node_allocator_->allocate > + (branch[0], branch[1]); + } + #endif + else + { + parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); + + return error_node(); + } + + parser_->state_.activate_side_effect("synthesize_swap_expression()"); + + return result; + } + + #ifndef exprtk_disable_sc_andor + inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(branch[0])) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (details::is_constant_node(branch[1]) && (0 == result)) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (result) + { + details::free_node(*node_allocator_, branch[0]); + details::free_node(*node_allocator_, branch[1]); + + return result; + } + else if (details::e_scand == operation) + { + return synthesize_expression(operation, branch); + } + else if (details::e_scor == operation) + { + return synthesize_expression(operation, branch); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) + { + return error_node(); + } + #endif + + #define basic_opr_switch_statements \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + case_stmt(details::e_pow , details::pow_op) \ + + #define extended_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op) \ + + #ifndef exprtk_disable_cardinal_pow_optimisation + template class IPowNode> + inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) + { + switch (p) + { + #define case_stmt(cp) \ + case cp : return node_allocator_-> \ + allocate > >(v); \ + + case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) + case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) + case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) + case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) + case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) + case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) + case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) + case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) + case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) + case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) + case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) + case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) + case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) + case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) + case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) + { + const bool not_recipricol = (c >= T(0)); + const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + + if (0 == p) + return node_allocator_->allocate_c(T(1)); + else if (std::equal_to()(T(2),c)) + { + return node_allocator_-> + template allocate_rr > >(v,v); + } + else + { + if (not_recipricol) + return cardinal_pow_optimisation_impl(v,p); + else + return cardinal_pow_optimisation_impl(v,p); + } + } + + inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const + { + return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + const bool not_recipricol = (c >= T(0)); + const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + + node_allocator_->free(branch[1]); + + if (0 == p) + { + details::free_all_nodes(*node_allocator_, branch); + + return node_allocator_->allocate_c(T(1)); + } + else if (not_recipricol) + return cardinal_pow_optimisation_impl(branch[0],p); + else + return cardinal_pow_optimisation_impl(branch[0],p); + } + #else + inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) + { + return error_node(); + } + + inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) + { + return false; + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) + { + return error_node(); + } + #endif + + struct synthesize_binary_ext_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool left_neg = is_neg_unary_node(branch[0]); + const bool right_neg = is_neg_unary_node(branch[1]); + + if (left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if ( + !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || + !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) + ) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + } + + switch (operation) + { + // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_add : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[1],branch[0]); + + default : break; + } + } + else if (left_neg && !right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + + switch (operation) + { + // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[1], branch[0]); + + // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + default : return error_node(); + } + } + } + else if (!left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + + switch (operation) + { + // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1]); + + // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1]); + + // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + default : return error_node(); + } + } + } + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate > > \ + (branch[0], branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_vob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, v, operation, branch[1], result); + + if (synthesis_result) + { + details::free_node(*expr_gen.node_allocator_,branch[1]); + return result; + } + } + #endif + + if ( + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[1])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[1])->operation(); + + if (details::e_neg == o) + { + const Type& v1 = static_cast(branch[1])->v(); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + + switch (operation) + { + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + default : break; + } + } + } + } + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_bov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[1])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, v, operation, branch[0], result); + + if (synthesis_result) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + + return result; + } + } + #endif + + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[0])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[0])->operation(); + + if (details::e_neg == o) + { + const Type& v0 = static_cast(branch[0])->v(); + + details::free_node(*expr_gen.node_allocator_,branch[0]); + + switch (operation) + { + case details::e_add : return expr_gen.node_allocator_-> + template allocate_rr > >(v,v0); + + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + default : break; + } + } + } + } + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[0])->value(); + + details::free_node(*expr_gen.node_allocator_,branch[0]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return branch[1]; + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return branch[1]; + + if (details::is_cob_node(branch[1])) + { + // Simplify expressions of the form: + // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) + // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x + if ( + (details::e_mul == operation) || + (details::e_add == operation) + ) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + + if (operation == cobnode->operation()) + { + switch (operation) + { + case details::e_add : cobnode->set_c(c + cobnode->c()); break; + case details::e_mul : cobnode->set_c(c * cobnode->c()); break; + default : return error_node(); + } + + return cobnode; + } + } + + if (operation == details::e_mul) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + switch (cob_opr) + { + case details::e_div : cobnode->set_c(c * cobnode->c()); break; + case details::e_mul : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + + return cobnode; + } + } + else if (operation == details::e_div) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + details::expression_node* new_cobnode = error_node(); + + switch (cob_opr) + { + case details::e_div : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + break; + + case details::e_mul : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + break; + + default : return error_node(); + } + + details::free_node(*expr_gen.node_allocator_,branch[1]); + + return new_cobnode; + } + } + } + #ifndef exprtk_disable_enhanced_features + else if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, c, operation, branch[1], result); + + if (synthesis_result) + { + details::free_node(*expr_gen.node_allocator_,branch[1]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_tt > > \ + (c, branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_boc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_), branch[1]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + + return expr_gen(std::numeric_limits::quiet_NaN()); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return branch[0]; + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return branch[0]; + + if (details::is_boc_node(branch[0])) + { + // Simplify expressions of the form: + // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 + // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 + if ( + (details::e_mul == operation) || + (details::e_add == operation) + ) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + + if (operation == bocnode->operation()) + { + switch (operation) + { + case details::e_add : bocnode->set_c(c + bocnode->c()); break; + case details::e_mul : bocnode->set_c(c * bocnode->c()); break; + default : return error_node(); + } + + return bocnode; + } + } + else if (operation == details::e_div) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if ( + (details::e_div == boc_opr) || + (details::e_mul == boc_opr) + ) + { + switch (boc_opr) + { + case details::e_div : bocnode->set_c(c * bocnode->c()); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + return bocnode; + } + } + else if (operation == details::e_pow) + { + // (v ^ c0) ^ c1 --> v ^(c0 * c1) + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if (details::e_pow == boc_opr) + { + bocnode->set_c(bocnode->c() * c); + + return bocnode; + } + } + } + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, c, operation, branch[0], result); + + if (synthesis_result) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cocob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (cob) o c --> cob + if (details::is_cob_node(branch[0])) + { + details::cob_base_node* cobnode = static_cast*>(branch[0]); + + const Type c = static_cast*>(branch[1])->value(); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(std::numeric_limits::quiet_NaN())); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + else if (std::equal_to()(T(1),c) && (details::e_div == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + + const bool op_addsub = (details::e_add == cobnode->operation()) || + (details::e_sub == cobnode->operation()) ; + + if (op_addsub) + { + switch (operation) + { + case details::e_add : cobnode->set_c(cobnode->c() + c); break; + case details::e_sub : cobnode->set_c(cobnode->c() - c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_mul == cobnode->operation()) + { + switch (operation) + { + case details::e_mul : cobnode->set_c(cobnode->c() * c); break; + case details::e_div : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(cobnode->c() * c); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (cobnode->c() / c, cobnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_, branch[0]); + } + } + + if (result) + { + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + // c o (cob) --> cob + else if (details::is_cob_node(branch[1])) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + + const Type c = static_cast*>(branch[0])->value(); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + + return branch[1]; + } + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + { + details::free_node(*expr_gen.node_allocator_, branch[0]); + + return branch[1]; + } + + if (details::e_add == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(), cobnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(), cobnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + details::free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + struct synthesize_coboc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (boc) o c --> boc + if (details::is_boc_node(branch[0])) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + + const Type c = static_cast*>(branch[1])->value(); + + if (details::e_add == bocnode->operation()) + { + switch (operation) + { + case details::e_add : bocnode->set_c(bocnode->c() + c); break; + case details::e_sub : bocnode->set_c(bocnode->c() - c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_mul == bocnode->operation()) + { + switch (operation) + { + case details::e_mul : bocnode->set_c(bocnode->c() * c); break; + case details::e_div : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0), c - bocnode->c()); + + details::free_node(*expr_gen.node_allocator_,branch[0]); + } + else if (details::e_sub == operation) + { + bocnode->set_c(bocnode->c() + c); + result = bocnode; + } + } + else if (details::e_div == bocnode->operation()) + { + switch (operation) + { + case details::e_div : bocnode->set_c(bocnode->c() * c); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + + if (result) + { + details::free_node(*expr_gen.node_allocator_, branch[1]); + } + } + + // c o (boc) --> boc + else if (details::is_boc_node(branch[1])) + { + details::boc_base_node* bocnode = static_cast*>(branch[1]); + + const Type c = static_cast*>(branch[0])->value(); + + if (details::e_add == bocnode->operation()) + { + if (details::e_add == operation) + { + bocnode->set_c(c + bocnode->c()); + result = bocnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - bocnode->c(), bocnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0), c - bocnode->c()); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c + bocnode->c(), bocnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(c * bocnode->c()); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / bocnode->c(), bocnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(bocnode->c() / c); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c * bocnode->c(), bocnode->move_branch(0)); + + details::free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + details::free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + #ifndef exprtk_disable_enhanced_features + inline bool synthesize_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2], + expression_node_ptr& result) + { + result = error_node(); + + if (!operation_optimisable(operation)) + return false; + + const std::string node_id = branch_to_id(branch); + + const typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); + + if (synthesize_map_.end() != itr) + { + result = itr->second((*this), operation, branch); + + return true; + } + else + return false; + } + + struct synthesize_vov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v1 = static_cast*>(branch[0])->ref(); + const Type& v2 = static_cast*>(branch[1])->ref(); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rr > > \ + (v1, v2); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*> (branch[0])->value(); + const Type& v = static_cast*>(branch[1])->ref (); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return static_cast*>(branch[1]); + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return static_cast*>(branch[1]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (c, v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_voc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref (); + const Type c = static_cast*> (branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_), branch[1]); + + if (expr_gen.cardinal_pow_optimisable(operation,c)) + { + if (std::equal_to()(T(1),c)) + return branch[0]; + else + return expr_gen.cardinal_pow_optimisation(v,c); + } + else if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + return expr_gen(std::numeric_limits::quiet_NaN()); + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return static_cast*>(branch[0]); + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return static_cast*>(branch[0]); + else if (std::equal_to()(T(1),c) && (details::e_div == operation)) + return static_cast*>(branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_sf3ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf3opr, + T0 t0, T1 t1, T2 t2) + { + switch (sf3opr) + { + #define case_stmt(op) \ + case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) + #undef case_stmt + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, + expression_node_ptr& result) + { + details::operator_type sf3opr; + + if (!expr_gen.sf3_optimisable(id,sf3opr)) + return false; + else + result = synthesize_sf3ext_expression::template process + (expr_gen, sf3opr, t0, t1, t2); + + return true; + } + }; + + struct synthesize_sf4ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf4opr, + T0 t0, T1 t1, T2 t2, T3 t3) + { + switch (sf4opr) + { + #define case_stmt0(op) \ + case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + + #define case_stmt1(op) \ + case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + + case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) + case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) + case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) + case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) + case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) + case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) + case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) + case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) + case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) + + case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) + case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) + case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) + case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) + case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) + case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) + case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) + case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) + case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) + case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) + case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) + case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) + case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) + case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) + case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) + case_stmt1(60) case_stmt1(61) + + #undef case_stmt0 + #undef case_stmt1 + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, T3 t3, + expression_node_ptr& result) + { + details::operator_type sf4opr; + + if (!expr_gen.sf4_optimisable(id,sf4opr)) + return false; + else + result = synthesize_sf4ext_expression::template process + (expr_gen, sf4opr, t0, t1, t2, t3); + + return true; + } + + // T o (sf3ext) + template + static inline bool compile_right(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_covov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vocov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovoc : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + default : return false; + } + } + + // (sf3ext) o T + template + static inline bool compile_left(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + + const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_covov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vocov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovoc : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + default : return false; + } + } + + template + static inline bool compile_right_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression::template compile + (expr_gen, id, t, t0, t1, t2, result); + } + else + return false; + } + + template + static inline bool compile_left_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression::template compile + (expr_gen, id, t0, t1, t2, t, result); + } + else + return false; + } + }; + + struct synthesize_vovov_expression0 + { + typedef typename vovov_t::type0 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, v2, result); + + exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vovov_expression1 + { + typedef typename vovov_t::type1 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 v2) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, v2, v1, result); + + exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vovoc_expression0 + { + typedef typename vovoc_t::type0 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + + exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vovoc_expression1 + { + typedef typename vovoc_t::type1 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 c) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = voc->v(); + const Type c = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, c, v1, result); + + exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vocov_expression0 + { + typedef typename vocov_t::type0 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v0 = voc->v(); + const Type c = voc->c(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + + exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vocov_expression1 + { + typedef typename vocov_t::type1 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (c o1 v1) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (c / v1) --> (vovoc) (v0 * v1) / c + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, v1, c, result); + + exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_covov_expression0 + { + typedef typename covov_t::type0 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c = cov->c(); + const Type& v0 = cov->v(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) / v1 --> (covov) c / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", c, v0, v1, result); + + exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_covov_expression1 + { + typedef typename covov_t::type1 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c) o0 (v0 o1 v1) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // c / (v0 / v1) --> (covov) (c * v1) / v0 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", c, v1, v0, result); + + exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_covoc_expression0 + { + typedef typename covoc_t::type0 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v) o1 (c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c0 = cov->c(); + const Type& v = cov->v(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v) + c1 --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0 + v) - c1 --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0 - v) + c1 --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0 - v) - c1 --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0 * v) * c1 --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0 * v) / c1 --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0 / v) * c1 --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0 / v) / c1 --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_covoc_expression1 + { + typedef typename covoc_t::type1 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (v o1 c1) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v = voc->v(); + const Type c1 = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (v + c1) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) + (v - c1) --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (v + c1) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (v - c1) --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) * (v * c1) --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) * (v / c1) --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (v * c1) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (v / c1) --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_cocov_expression0 + { + typedef typename cocov_t::type0 node_type; + static inline expression_node_ptr process(expression_generator&, + const details::operator_type&, + expression_node_ptr (&)[2]) + { + // (c0 o0 c1) o1 (v) - Not possible. + return error_node(); + } + }; + + struct synthesize_cocov_expression1 + { + typedef typename cocov_t::type1 node_type; + typedef typename cocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (c1 o1 v) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type c1 = cov->c(); + const Type& v = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (c1 + v) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) + (c1 - v) --> (cov) (c0 + c1) - v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) - (c1 + v) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (c1 - v) --> (cov) (c0 - c1) + v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) * (c1 * v) --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) * (c1 / v) --> (cov) (c0 * c1) / v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) / (c1 * v) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (c1 / v) --> (cov) (c0 / c1) * v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, c1, v, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vococ_expression0 + { + typedef typename vococ_t::type0 node_type; + typedef typename vococ_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v o0 c0) o1 (c1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v = voc->v(); + const Type& c0 = voc->c(); + const Type& c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v + c0) + c1 --> (voc) v + (c0 + c1) + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 + c1); + } + // (v + c0) - c1 --> (voc) v + (c0 - c1) + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 - c1); + } + // (v - c0) + c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c1 - c0); + } + // (v - c0) - c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 + c1); + } + // (v * c0) * c1 --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + // (v * c0) / c1 --> (voc) v * (c0 / c1) + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 / c1); + } + // (v / c0) * c1 --> (voc) v * (c1 / c0) + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c1 / c0); + } + // (v / c0) / c1 --> (voc) v / (c0 * c1) + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) + else if ((details::e_pow == o0) && (details::e_pow == o1)) + { + exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v, c0, c1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v, c0, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vococ_expression1 + { + typedef typename vococ_t::type0 node_type; + + static inline expression_node_ptr process(expression_generator&, + const details::operator_type&, + expression_node_ptr (&)[2]) + { + // (v) o0 (c0 o1 c1) - Not possible. + exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); + return error_node(); + } + }; + + struct synthesize_vovovov_expression0 + { + typedef typename vovovov_t::type0 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 v3) + const details::vov_base_node* vov0 = static_cast*>(branch[0]); + const details::vov_base_node* vov1 = static_cast*>(branch[1]); + const Type& v0 = vov0->v0(); + const Type& v1 = vov0->v1(); + const Type& v2 = vov1->v0(); + const Type& v3 = vov1->v1(); + const details::operator_type o0 = vov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov1->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); + + exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); + + exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovoc_expression0 + { + typedef typename vovovoc_t::type0 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = voc->v (); + const Type c = voc->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + + exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + + exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovocov_expression0 + { + typedef typename vovocov_t::type0 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c o2 v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = cov->v (); + const Type c = cov->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + + exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + + exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovov_expression0 + { + typedef typename vocovov_t::type0 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1 o2 v2) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = voc->c (); + const Type& v0 = voc->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); + + exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); + + exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovov_expression0 + { + typedef typename covovov_t::type0 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1 o2 v2) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = cov->c (); + const Type& v0 = cov->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); + + exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); + + exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covocov_expression0 + { + typedef typename covocov_t::type0 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (c1 o2 v1) + const details::cov_base_node* cov0 = static_cast*>(branch[0]); + const details::cov_base_node* cov1 = static_cast*>(branch[1]); + const Type c0 = cov0->c(); + const Type& v0 = cov0->v(); + const Type c1 = cov1->c(); + const Type& v1 = cov1->v(); + const details::operator_type o0 = cov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov1->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); + + exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovoc_expression0 + { + typedef typename vocovoc_t::type0 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (v1 o2 c1) + const details::voc_base_node* voc0 = static_cast*>(branch[0]); + const details::voc_base_node* voc1 = static_cast*>(branch[1]); + const Type c0 = voc0->c(); + const Type& v0 = voc0->v(); + const Type c1 = voc1->c(); + const Type& v1 = voc1->v(); + const details::operator_type o0 = voc0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc1->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); + + exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); + + exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); + + exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c + else if ( + (std::equal_to()(c0,c1)) && + (details::e_div == o0) && + (details::e_div == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "(t+t)/t"; break; + case details::e_sub : specfunc = "(t-t)/t"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, v0, v1, c0, result); + + exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovoc_expression0 + { + typedef typename covovoc_t::type0 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (v1 o2 c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = cov->c(); + const Type& v0 = cov->v(); + const Type c1 = voc->c(); + const Type& v1 = voc->v(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); + + exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vococov_expression0 + { + typedef typename vococov_t::type0 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (c1 o2 v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = voc->c(); + const Type& v0 = voc->v(); + const Type c1 = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); + + exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + + exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); + + exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovov_expression1 + { + typedef typename vovovov_t::type1 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 v3)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen,id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovovoc_expression1 + { + typedef typename vovovoc_t::type1 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 c)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovocov_expression1 + { + typedef typename vovocov_t::type1 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (c o2 v2)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vocovov_expression1 + { + typedef typename vocovov_t::type1 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c o1 (v1 o2 v2)) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covovov_expression1 + { + typedef typename covovov_t::type1 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 (v0 o1 (v1 o2 v2)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covocov_expression1 + { + typedef typename covocov_t::type1 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (c1 o2 v1)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vocovoc_expression1 + { + typedef typename vocovoc_t::type1 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (v1 o2 c2)) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covovoc_expression1 + { + typedef typename covovoc_t::type1 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (v1 o2 c1)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vococov_expression1 + { + typedef typename vococov_t::type1 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (c1 o2 v1)) + typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; + + const lcl_cocov_t* cocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = cocov->t0(); + const Type c1 = cocov->t1(); + const Type& v1 = cocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = cocov->f0(); + binary_functor_t f2 = cocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovovov_expression2 + { + typedef typename vovovov_t::type2 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovoc_expression2 + { + typedef typename vovovoc_t::type2 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 c) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovocov_expression2 + { + typedef typename vovocov_t::type2 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 c) o2 v2) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovov_expression2 + { + typedef typename vocovov_t::type2 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c o1 v1) o2 v2) + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovov_expression2 + { + typedef typename covovov_t::type2 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covocov_expression2 + { + typedef typename covocov_t::type2 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 c1) o2 v1) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovoc_expression2 + { + typedef typename vocovoc_t::type2 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c0 o1 v1) o2 c1) + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovoc_expression2 + { + typedef typename covovoc_t::type2 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 v1) o2 c1) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vococov_expression2 + { + typedef typename vococov_t::type2 node_type; + static inline expression_node_ptr process(expression_generator&, + const details::operator_type&, + expression_node_ptr (&)[2]) + { + // v0 o0 ((c0 o1 c1) o2 v1) - Not possible + exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, + const details::operator_type, + const details::operator_type) + { + return "INVALID"; + } + }; + + struct synthesize_vovovov_expression3 + { + typedef typename vovovov_t::type3 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 v3 + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovoc_expression3 + { + typedef typename vovovoc_t::type3 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 c + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovocov_expression3 + { + typedef typename vovocov_t::type3 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 c) o2 v2 + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovov_expression3 + { + typedef typename vocovov_t::type3 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c) o1 v1) o2 v2 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovov_expression3 + { + typedef typename covovov_t::type3 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 v0) o1 v1) o2 v2 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covocov_expression3 + { + typedef typename covocov_t::type3 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 c1) o2 v1 + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovoc_expression3 + { + typedef typename vocovoc_t::type3 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 v1) o2 c1 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovoc_expression3 + { + typedef typename covovoc_t::type3 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 v1) o2 c1 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vococov_expression3 + { + typedef typename vococov_t::type3 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 c1) o2 v1 + typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; + + const lcl_vococ_t* vococ = static_cast(branch[0]); + const Type& v0 = vococ->t0(); + const Type c0 = vococ->t1(); + const Type c1 = vococ->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); + const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vococ->f0(); + binary_functor_t f1 = vococ->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovov_expression4 + { + typedef typename vovovov_t::type4 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 (v1 o1 v2)) o2 v3 + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovoc_expression4 + { + typedef typename vovovoc_t::type4 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 v2)) o2 c) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovocov_expression4 + { + typedef typename vovocov_t::type4 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 c)) o2 v1) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovov_expression4 + { + typedef typename vocovov_t::type4 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c o1 v1)) o2 v2) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovov_expression4 + { + typedef typename covovov_t::type4 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 (v0 o1 v1)) o2 v2) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covocov_expression4 + { + typedef typename covocov_t::type4 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 c1)) o2 v1) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovoc_expression4 + { + typedef typename vocovoc_t::type4 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c0 o1 v1)) o2 c1) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovoc_expression4 + { + typedef typename covovoc_t::type4 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 v1)) o2 c1) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vococov_expression4 + { + typedef typename vococov_t::type4 node_type; + static inline expression_node_ptr process(expression_generator&, + const details::operator_type&, + expression_node_ptr (&)[2]) + { + // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible + exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, + const details::operator_type, + const details::operator_type) + { + return "INVALID"; + } + }; + #endif + + inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + // Definition: uv o uv + details::operator_type o0 = static_cast*>(branch[0])->operation(); + details::operator_type o1 = static_cast*>(branch[1])->operation(); + const Type& v0 = static_cast*>(branch[0])->v(); + const Type& v1 = static_cast*>(branch[1])->v(); + unary_functor_t u0 = reinterpret_cast (0); + unary_functor_t u1 = reinterpret_cast (0); + binary_functor_t f = reinterpret_cast(0); + + if (!valid_operator(o0,u0)) + return error_node(); + else if (!valid_operator(o1,u1)) + return error_node(); + else if (!valid_operator(operation,f)) + return error_node(); + + expression_node_ptr result = error_node(); + + if ( + (details::e_neg == o0) && + (details::e_neg == o1) + ) + { + switch (operation) + { + // (-v0 + -v1) --> -(v0 + v1) + case details::e_add : result = (*this)(details::e_neg, + node_allocator_-> + allocate_rr > >(v0, v1)); + exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); + break; + + // (-v0 - -v1) --> (v1 - v0) + case details::e_sub : result = node_allocator_-> + allocate_rr > >(v1, v0); + exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); + break; + + // (-v0 * -v1) --> (v0 * v1) + case details::e_mul : result = node_allocator_-> + allocate_rr > >(v0, v1); + exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); + break; + + // (-v0 / -v1) --> (v0 / v1) + case details::e_div : result = node_allocator_-> + allocate_rr > >(v0, v1); + exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); + break; + + default : break; + } + } + + if (0 == result) + { + result = node_allocator_-> + allocate_rrrrr >(v0, v1, u0, u1, f); + } + + details::free_all_nodes(*node_allocator_,branch); + return result; + } + + #undef basic_opr_switch_statements + #undef extended_opr_switch_statements + #undef unary_opr_switch_statements + + #ifndef exprtk_disable_string_capabilities + + #define string_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_in , details::in_op ) \ + case_stmt(details::e_like , details::like_op ) \ + case_stmt(details::e_ilike , details::ilike_op) \ + + template + inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0) + { + switch (opr) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp0); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp1) + { + switch (opr) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0, range_t rp1) + { + switch (opr) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_tttt >,T0,T1> \ + (s0, s1, rp0, rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) + { + switch (opr) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_tt >,T0,T1>(s0, s1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + + details::free_node(*node_allocator_,branch[1]); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast* >(branch[1])->ref(); + + details::free_node(*node_allocator_,branch[0]); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast* >(branch[1])->ref (); + range_t rp1 = static_cast* >(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast* >(branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast* >(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast* >(branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast* >(branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*> (branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + + expression_node_ptr result = error_node(); + + if (details::e_add == opr) + result = node_allocator_->allocate_c >(s0 + s1); + else if (details::e_in == opr) + result = node_allocator_->allocate_c >(details::in_op ::process(s0,s1)); + else if (details::e_like == opr) + result = node_allocator_->allocate_c >(details::like_op ::process(s0,s1)); + else if (details::e_ilike == opr) + result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); + else + { + expression_node_ptr temp = synthesize_sos_expression_impl(opr, s0, s1); + + const Type v = temp->value(); + + details::free_node(*node_allocator_,temp); + + result = node_allocator_->allocate(v); + } + + details::free_all_nodes(*node_allocator_,branch); + + return result; + } + + inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast* >(branch[0])->str (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast* >(branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast* >(branch[1])->ref (); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast* >(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*> (branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast* >(branch[1])->str (); + const range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast*>(branch[1])->str (); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + switch (opr) + { + #define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt > > \ + (opr, branch[0], branch[1]); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + const bool b0_is_s = details::is_string_node (branch[0]); + const bool b0_is_cs = details::is_const_string_node (branch[0]); + const bool b0_is_sr = details::is_string_range_node (branch[0]); + const bool b0_is_csr = details::is_const_string_range_node(branch[0]); + + const bool b1_is_s = details::is_string_node (branch[1]); + const bool b1_is_cs = details::is_const_string_node (branch[1]); + const bool b1_is_sr = details::is_string_range_node (branch[1]); + const bool b1_is_csr = details::is_const_string_range_node(branch[1]); + + const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || + details::is_genricstring_range_node(branch[0]) || + details::is_string_concat_node (branch[0]) || + details::is_string_function_node (branch[0]) || + details::is_string_condition_node (branch[0]) || + details::is_string_ccondition_node (branch[0]) || + details::is_string_vararg_node (branch[0]) ; + + const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || + details::is_genricstring_range_node(branch[1]) || + details::is_string_concat_node (branch[1]) || + details::is_string_function_node (branch[1]) || + details::is_string_condition_node (branch[1]) || + details::is_string_ccondition_node (branch[1]) || + details::is_string_vararg_node (branch[1]) ; + + if (details::e_add == opr) + { + if (!b0_is_cs || !b1_is_cs) + { + return synthesize_expression(opr,branch); + } + } + + if (b0_is_gen || b1_is_gen) + { + return synthesize_strogen_expression(opr,branch); + } + else if (b0_is_s) + { + if (b1_is_s ) return synthesize_sos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); + } + else if (b0_is_cs) + { + if (b1_is_s ) return synthesize_csos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); + } + else if (b0_is_sr) + { + if (b1_is_s ) return synthesize_sros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); + } + else if (b0_is_csr) + { + if (b1_is_s ) return synthesize_csros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); + } + + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) + { + if (details::e_inrange != opr) + return error_node(); + else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + const std::string s2 = static_cast*>(branch[2])->str(); + + const Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + + details::free_all_nodes(*node_allocator_,branch); + + return node_allocator_->allocate_c >(v); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + std::string& s2 = static_cast*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast* >(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast* >(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + std::string& s2 = static_cast* >(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[1]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string& s0 = static_cast* >(branch[0])->ref(); + std::string& s1 = static_cast* >(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details:: is_string_node(branch[1]) && + details:: is_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast* >(branch[1])->ref(); + std::string& s2 = static_cast* >(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + /* + Note: The following are the type promotion rules + that relate to operations that include 'null': + 0. null ==/!= null --> true false + 1. null operation null --> null + 2. x ==/!= null --> true/false + 3. null ==/!= x --> true/false + 4. x operation null --> x + 5. null operation x --> x + */ + + typedef typename details::null_eq_node nulleq_node_t; + + const bool b0_null = details::is_null_node(branch[0]); + const bool b1_null = details::is_null_node(branch[1]); + + if (b0_null && b1_null) + { + expression_node_ptr result = error_node(); + + if (details::e_eq == operation) + result = node_allocator_->allocate_c(T(1)); + else if (details::e_ne == operation) + result = node_allocator_->allocate_c(T(0)); + + if (result) + { + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return result; + } + + details::free_node(*node_allocator_,branch[1]); + + return branch[0]; + } + else if (details::e_eq == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],true); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (details::e_ne == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],false); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (b0_null) + { + details::free_node(*node_allocator_,branch[0]); + branch[0] = branch[1]; + branch[1] = error_node(); + } + else if (b1_null) + { + details::free_node(*node_allocator_,branch[1]); + branch[1] = error_node(); + } + + if ( + (details::e_add == operation) || (details::e_sub == operation) || + (details::e_mul == operation) || (details::e_div == operation) || + (details::e_mod == operation) || (details::e_pow == operation) + ) + { + return branch[0]; + } + + details::free_node(*node_allocator_, branch[0]); + + if ( + (details::e_lt == operation) || (details::e_lte == operation) || + (details::e_gt == operation) || (details::e_gte == operation) || + (details::e_and == operation) || (details::e_nand == operation) || + (details::e_or == operation) || (details::e_nor == operation) || + (details::e_xor == operation) || (details::e_xnor == operation) || + (details::e_in == operation) || (details::e_like == operation) || + (details::e_ilike == operation) + ) + { + return node_allocator_->allocate_c(T(0)); + } + + return node_allocator_->allocate >(); + } + + template + inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) + { + if ( + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) + ) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ((details::e_default != operation)) + { + // Attempt simple constant folding optimisation. + expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); + + if (is_constant_foldable(branch)) + { + const Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + else + return expression_point; + } + else + return error_node(); + } + + template + inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) + { + if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + typedef typename details::function_N_node function_N_node_t; + + // Attempt simple constant folding optimisation. + + expression_node_ptr expression_point = node_allocator_->allocate(f); + function_N_node_t* func_node_ptr = dynamic_cast(expression_point); + + if (0 == func_node_ptr) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else + func_node_ptr->init_branches(branch); + + if (is_constant_foldable(branch) && !f->has_side_effects()) + { + Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + + parser_->state_.activate_side_effect("synthesize_expression(function)"); + + return expression_point; + } + + bool strength_reduction_enabled_; + details::node_allocator* node_allocator_; + synthesize_map_t synthesize_map_; + unary_op_map_t* unary_op_map_; + binary_op_map_t* binary_op_map_; + inv_binary_op_map_t* inv_binary_op_map_; + sf3_map_t* sf3_map_; + sf4_map_t* sf4_map_; + parser_t* parser_; + }; // class expression_generator + + inline void set_error(const parser_error::type& error_type) + { + error_list_.push_back(error_type); + } + + inline void remove_last_error() + { + if (!error_list_.empty()) + { + error_list_.pop_back(); + } + } + + inline void set_synthesis_error(const std::string& synthesis_error_message) + { + if (synthesis_error_.empty()) + { + synthesis_error_ = synthesis_error_message; + } + } + + inline void register_local_vars(expression& e) + { + for (std::size_t i = 0; i < sem_.size(); ++i) + { + scope_element& se = sem_.get_element(i); + + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_vecelem == se.type) + ) + { + if (se.var_node) + { + e.register_local_var(se.var_node); + } + + if (se.data) + { + e.register_local_data(se.data, 1, 0); + } + } + else if (scope_element::e_vector == se.type) + { + if (se.vec_node) + { + e.register_local_var(se.vec_node); + } + + if (se.data) + { + e.register_local_data(se.data, se.size, 1); + } + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + if (se.str_node) + { + e.register_local_var(se.str_node); + } + + if (se.data) + { + e.register_local_data(se.data, se.size, 2); + } + } + #endif + + se.var_node = 0; + se.vec_node = 0; + #ifndef exprtk_disable_string_capabilities + se.str_node = 0; + #endif + se.data = 0; + se.ref_count = 0; + se.active = false; + } + } + + inline void register_return_results(expression& e) + { + e.register_return_results(results_context_); + results_context_ = 0; + } + + inline void load_unary_operations_map(unary_op_map_t& m) + { + #define register_unary_op(Op, UnaryFunctor) \ + m.insert(std::make_pair(Op,UnaryFunctor::process)); \ + + register_unary_op(details::e_abs , details::abs_op ) + register_unary_op(details::e_acos , details::acos_op ) + register_unary_op(details::e_acosh , details::acosh_op) + register_unary_op(details::e_asin , details::asin_op ) + register_unary_op(details::e_asinh , details::asinh_op) + register_unary_op(details::e_atanh , details::atanh_op) + register_unary_op(details::e_ceil , details::ceil_op ) + register_unary_op(details::e_cos , details::cos_op ) + register_unary_op(details::e_cosh , details::cosh_op ) + register_unary_op(details::e_exp , details::exp_op ) + register_unary_op(details::e_expm1 , details::expm1_op) + register_unary_op(details::e_floor , details::floor_op) + register_unary_op(details::e_log , details::log_op ) + register_unary_op(details::e_log10 , details::log10_op) + register_unary_op(details::e_log2 , details::log2_op ) + register_unary_op(details::e_log1p , details::log1p_op) + register_unary_op(details::e_neg , details::neg_op ) + register_unary_op(details::e_pos , details::pos_op ) + register_unary_op(details::e_round , details::round_op) + register_unary_op(details::e_sin , details::sin_op ) + register_unary_op(details::e_sinc , details::sinc_op ) + register_unary_op(details::e_sinh , details::sinh_op ) + register_unary_op(details::e_sqrt , details::sqrt_op ) + register_unary_op(details::e_tan , details::tan_op ) + register_unary_op(details::e_tanh , details::tanh_op ) + register_unary_op(details::e_cot , details::cot_op ) + register_unary_op(details::e_sec , details::sec_op ) + register_unary_op(details::e_csc , details::csc_op ) + register_unary_op(details::e_r2d , details::r2d_op ) + register_unary_op(details::e_d2r , details::d2r_op ) + register_unary_op(details::e_d2g , details::d2g_op ) + register_unary_op(details::e_g2d , details::g2d_op ) + register_unary_op(details::e_notl , details::notl_op ) + register_unary_op(details::e_sgn , details::sgn_op ) + register_unary_op(details::e_erf , details::erf_op ) + register_unary_op(details::e_erfc , details::erfc_op ) + register_unary_op(details::e_ncdf , details::ncdf_op ) + register_unary_op(details::e_frac , details::frac_op ) + register_unary_op(details::e_trunc , details::trunc_op) + #undef register_unary_op + } + + inline void load_binary_operations_map(binary_op_map_t& m) + { + typedef typename binary_op_map_t::value_type value_type; + + #define register_binary_op(Op, BinaryFunctor) \ + m.insert(value_type(Op,BinaryFunctor::process)); \ + + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) + #undef register_binary_op + } + + inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) + { + typedef typename inv_binary_op_map_t::value_type value_type; + + #define register_binary_op(Op, BinaryFunctor) \ + m.insert(value_type(BinaryFunctor::process,Op)); \ + + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) + #undef register_binary_op + } + + inline void load_sf3_map(sf3_map_t& sf3_map) + { + typedef std::pair pair_t; + + #define register_sf3(Op) \ + sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) + register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) + register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) + register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) + register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) + register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) + register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) + register_sf3(28) register_sf3(29) register_sf3(30) + #undef register_sf3 + + #define register_sf3_extid(Id, Op) \ + sf3_map[Id] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf3_extid("(t-t)-t",23) // (t-t)-t --> t-(t+t) + #undef register_sf3_extid + } + + inline void load_sf4_map(sf4_map_t& sf4_map) + { + typedef std::pair pair_t; + + #define register_sf4(Op) \ + sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) + register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) + register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) + register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) + register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) + register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) + register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) + register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) + register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) + #undef register_sf4 + + #define register_sf4ext(Op) \ + sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ + + register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) + register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) + register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) + register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) + register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) + register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) + register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) + register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) + register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) + register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) + register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) + register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) + register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) + register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) + register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) + register_sf4ext(60) register_sf4ext(61) + #undef register_sf4ext + } + + inline results_context_t& results_ctx() + { + if (0 == results_context_) + { + results_context_ = new results_context_t(); + } + + return (*results_context_); + } + + inline void return_cleanup() + { + #ifndef exprtk_disable_return_statement + if (results_context_) + { + delete results_context_; + results_context_ = 0; + } + + state_.return_stmt_present = false; + #endif + } + + private: + + parser(const parser&) exprtk_delete; + parser& operator=(const parser&) exprtk_delete; + + settings_store settings_; + expression_generator expression_generator_; + details::node_allocator node_allocator_; + symtab_store symtab_store_; + dependent_entity_collector dec_; + std::deque error_list_; + std::deque brkcnt_list_; + parser_state state_; + bool resolve_unknown_symbol_; + results_context_t* results_context_; + unknown_symbol_resolver* unknown_symbol_resolver_; + unknown_symbol_resolver default_usr_; + base_ops_map_t base_ops_map_; + unary_op_map_t unary_op_map_; + binary_op_map_t binary_op_map_; + inv_binary_op_map_t inv_binary_op_map_; + sf3_map_t sf3_map_; + sf4_map_t sf4_map_; + std::string synthesis_error_; + scope_element_manager sem_; + + lexer::helper::helper_assembly helper_assembly_; + + lexer::helper::commutative_inserter commutative_inserter_; + lexer::helper::operator_joiner operator_joiner_2_; + lexer::helper::operator_joiner operator_joiner_3_; + lexer::helper::symbol_replacer symbol_replacer_; + lexer::helper::bracket_checker bracket_checker_; + lexer::helper::numeric_checker numeric_checker_; + lexer::helper::sequence_validator sequence_validator_; + lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; + + loop_runtime_check_ptr loop_runtime_check_; + + template + friend void details::disable_type_checking(ParserType& p); + }; // class parser + + namespace details + { + template + struct collector_helper + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef typename parser_t::unknown_symbol_resolver usr_t; + + struct resolve_as_vector : public parser_t::unknown_symbol_resolver + { + typedef exprtk::parser parser_t; + + resolve_as_vector() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string&) + { + static T v[1]; + symbol_table.add_vector(unknown_symbol,v); + return true; + } + }; + + static inline bool collection_pass(const std::string& expression_string, + std::set& symbol_set, + const bool collect_variables, + const bool collect_functions, + const bool vector_pass, + symbol_table_t& ext_symbol_table) + { + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + resolve_as_vector vect_resolver; + + expression.register_symbol_table(symbol_table ); + expression.register_symbol_table(ext_symbol_table); + + if (vector_pass) + parser.enable_unknown_symbol_resolver(&vect_resolver); + else + parser.enable_unknown_symbol_resolver(); + + if (collect_variables) + parser.dec().collect_variables() = true; + + if (collect_functions) + parser.dec().collect_functions() = true; + + bool pass_result = false; + + details::disable_type_checking(parser); + + if (parser.compile(expression_string, expression)) + { + pass_result = true; + + std::deque symb_list; + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_set.insert(symb_list[i].first); + } + } + + return pass_result; + } + }; + } + + template class Sequence> + inline bool collect_variables(const std::string& expression, + Sequence& symbol_list) + { + typedef double T; + typedef details::collector_helper collect_t; + + collect_t::symbol_table_t null_symbol_table; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, null_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_variables(const std::string& expression, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef details::collector_helper collect_t; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, extrnl_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expression, + Sequence& symbol_list) + { + typedef double T; + typedef details::collector_helper collect_t; + + collect_t::symbol_table_t null_symbol_table; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, null_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expression, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef details::collector_helper collect_t; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, extrnl_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template + inline T integrate(const expression& e, + T& x, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + if (r0 > r1) + return T(0); + + const T h = (r1 - r0) / (T(2) * number_of_intervals); + T total_area = T(0); + + for (std::size_t i = 0; i < number_of_intervals; ++i) + { + x = r0 + T(2) * i * h; + const T y0 = e.value(); x += h; + const T y1 = e.value(); x += h; + const T y2 = e.value(); x += h; + total_area += h * (y0 + T(4) * y1 + y2) / T(3); + } + + return total_area; + } + + template + inline T integrate(const expression& e, + const std::string& variable_name, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + return std::numeric_limits::quiet_NaN(); + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = integrate(e, x, r0, r1, number_of_intervals); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T derivative(const expression& e, + T& x, + const T& h = T(0.00000001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); + } + + template + inline T second_derivative(const expression& e, + T& x, + const T& h = T(0.00001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + const T y = e.value(); + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); + } + + template + inline T third_derivative(const expression& e, + T& x, + const T& h = T(0.0001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); + } + + template + inline T derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00000001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T second_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = second_derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T third_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.0001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = third_derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + /* + Note: The following 'compute' routines are simple helpers, + for quickly setting up the required pieces of code in order + to evaluate an expression. By virtue of how they operate + there will be an overhead with regards to their setup and + teardown and hence should not be used in time critical + sections of code. + Furthermore they only assume a small sub set of variables, + no string variables or user defined functions. + */ + template + inline bool compute(const std::string& expression_string, T& result) + { + // No variables + symbol_table symbol_table; + symbol_table.add_constants(); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, + T& result) + { + // Only 'x' + static const std::string x_var("x"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T&x, const T& y, + T& result) + { + // Only 'x' and 'y' + static const std::string x_var("x"); + static const std::string y_var("y"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, const T& y, const T& z, + T& result) + { + // Only 'x', 'y' or 'z' + static const std::string x_var("x"); + static const std::string y_var("y"); + static const std::string z_var("z"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + symbol_table.add_constant(z_var,z); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + class polynomial : public ifunction + { + private: + + template + struct poly_impl { }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, + const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, + const Type c0) + { + // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, + const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, + const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((c3 * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_2x^2 + c_1x^1 + c_0x^0 + return ((c2 * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c1, const Type c0) + { + // p(x) = c_1x^1 + c_0x^0 + return (c1 * x + c0); + } + }; + + public: + + using ifunction::operator(); + + polynomial() + : ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) + { + disable_has_side_effects(*this); + } + + virtual ~polynomial() {} + + #define poly_rtrn(NN) \ + return (NN != N) ? std::numeric_limits::quiet_NaN() : + + inline virtual T operator() (const T& x, const T& c1, const T& c0) + { + poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, + const T& c0) + { + poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, + const T& c1, const T& c0) + { + poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, + const T& c2, const T& c1, const T& c0) + { + poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, + const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, + const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, + const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, + const T& c0) + { + poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, + const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, + const T& c1, const T& c0) + { + poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, + const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, + const T& c2, const T& c1, const T& c0) + { + poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, + const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, + const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + #undef poly_rtrn + + inline virtual T operator() () + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual T operator() (const T&) + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual T operator() (const T&, const T&) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + template + class function_compositor + { + public: + + typedef exprtk::expression expression_t; + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::settings_store settings_t; + + struct function + { + function() + {} + + function(const std::string& n) + : name_(n) + {} + + function(const std::string& name, + const std::string& expression) + : name_(name) + , expression_(expression) + {} + + function(const std::string& name, + const std::string& expression, + const std::string& v0) + : name_(name) + , expression_(expression) + { + v_.push_back(v0); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1) + : name_(name) + , expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2) + : name_(name) + , expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3) + : name_(name) + , expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3, + const std::string& v4) + : name_(name) + , expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + v_.push_back(v4); + } + + inline function& name(const std::string& n) + { + name_ = n; + return (*this); + } + + inline function& expression(const std::string& e) + { + expression_ = e; + return (*this); + } + + inline function& var(const std::string& v) + { + v_.push_back(v); + return (*this); + } + + std::string name_; + std::string expression_; + std::deque v_; + }; + + private: + + struct base_func : public exprtk::ifunction + { + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; + typedef std::pair lvarref_t; + typedef std::vector lvr_vec_t; + + using exprtk::ifunction::operator(); + + base_func(const std::size_t& pc = 0) + : exprtk::ifunction(pc) + , local_var_stack_size(0) + , stack_depth(0) + { + v.resize(pc); + } + + virtual ~base_func() {} + + #define exprtk_assign(Index) \ + (*v[Index]) = v##Index; \ + + inline void update(const T& v0) + { + exprtk_assign(0) + } + + inline void update(const T& v0, const T& v1) + { + exprtk_assign(0) exprtk_assign(1) + } + + inline void update(const T& v0, const T& v1, const T& v2) + { + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3) + { + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) + exprtk_assign(4) + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) + exprtk_assign(4) exprtk_assign(5) + } + + #ifdef exprtk_assign + #undef exprtk_assign + #endif + + inline function_t& setup(expression_t& expr) + { + expression = expr; + + typedef typename expression_t::control_block::local_data_list_t ldl_t; + + const ldl_t ldl = expr.local_data_list(); + + std::vector index_list; + + for (std::size_t i = 0; i < ldl.size(); ++i) + { + if (ldl[i].size) + { + index_list.push_back(i); + } + } + + std::size_t input_param_count = 0; + + for (std::size_t i = 0; i < index_list.size(); ++i) + { + const std::size_t index = index_list[i]; + + if (i < (index_list.size() - v.size())) + { + lv.push_back( + std::make_pair( + reinterpret_cast(ldl[index].pointer), + ldl[index].size)); + + local_var_stack_size += ldl[index].size; + } + else + v[input_param_count++] = reinterpret_cast(ldl[index].pointer); + } + + clear_stack(); + + return (*this); + } + + inline void pre() + { + if (stack_depth++) + { + if (!v.empty()) + { + var_t var_stack(v.size(),T(0)); + copy(v,var_stack); + param_stack.push_back(var_stack); + } + + if (!lv.empty()) + { + var_t local_var_stack(local_var_stack_size,T(0)); + copy(lv,local_var_stack); + local_stack.push_back(local_var_stack); + } + } + } + + inline void post() + { + if (--stack_depth) + { + if (!v.empty()) + { + copy(param_stack.back(),v); + param_stack.pop_back(); + } + + if (!lv.empty()) + { + copy(local_stack.back(),lv); + local_stack.pop_back(); + } + } + } + + void copy(const varref_t& src_v, var_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + dest_v[i] = (*src_v[i]); + } + } + + void copy(const var_t& src_v, varref_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + (*dest_v[i]) = src_v[i]; + } + } + + void copy(const lvr_vec_t& src_v, var_t& dest_v) + { + typename var_t::iterator itr = dest_v.begin(); + typedef typename std::iterator_traits::difference_type diff_t; + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = src_v[i]; + + if (1 == vr.second) + *itr++ = (*vr.first); + else + { + std::copy(vr.first, vr.first + vr.second, itr); + itr += static_cast(vr.second); + } + } + } + + void copy(const var_t& src_v, lvr_vec_t& dest_v) + { + typename var_t::const_iterator itr = src_v.begin(); + typedef typename std::iterator_traits::difference_type diff_t; + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = dest_v[i]; + + if (1 == vr.second) + (*vr.first) = *itr++; + else + { + std::copy(itr, itr + static_cast(vr.second), vr.first); + itr += static_cast(vr.second); + } + } + } + + inline void clear_stack() + { + for (std::size_t i = 0; i < v.size(); ++i) + { + (*v[i]) = 0; + } + } + + inline virtual T value(expression_t& e) + { + return e.value(); + } + + expression_t expression; + varref_t v; + lvr_vec_t lv; + std::size_t local_var_stack_size; + std::size_t stack_depth; + std::deque param_stack; + std::deque local_stack; + }; + + typedef std::map funcparam_t; + + struct func_0param : public base_func + { + using exprtk::ifunction::operator(); + + func_0param() : base_func(0) {} + + inline T operator() () + { + return this->value(base_func::expression); + } + }; + + typedef const T& type; + + template + struct scoped_bft + { + explicit scoped_bft(BaseFuncType& bft) + : bft_(bft) + { + bft_.pre (); + } + + ~scoped_bft() + { + bft_.post(); + } + + BaseFuncType& bft_; + + private: + + scoped_bft(const scoped_bft&) exprtk_delete; + scoped_bft& operator=(const scoped_bft&) exprtk_delete; + }; + + struct func_1param : public base_func + { + using exprtk::ifunction::operator(); + + func_1param() : base_func(1) {} + + inline T operator() (type v0) + { + scoped_bft sb(*this); + base_func::update(v0); + return this->value(base_func::expression); + } + }; + + struct func_2param : public base_func + { + using exprtk::ifunction::operator(); + + func_2param() : base_func(2) {} + + inline T operator() (type v0, type v1) + { + scoped_bft sb(*this); + base_func::update(v0, v1); + return this->value(base_func::expression); + } + }; + + struct func_3param : public base_func + { + using exprtk::ifunction::operator(); + + func_3param() : base_func(3) {} + + inline T operator() (type v0, type v1, type v2) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2); + return this->value(base_func::expression); + } + }; + + struct func_4param : public base_func + { + using exprtk::ifunction::operator(); + + func_4param() : base_func(4) {} + + inline T operator() (type v0, type v1, type v2, type v3) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3); + return this->value(base_func::expression); + } + }; + + struct func_5param : public base_func + { + using exprtk::ifunction::operator(); + + func_5param() : base_func(5) {} + + inline T operator() (type v0, type v1, type v2, type v3, type v4) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3, v4); + return this->value(base_func::expression); + } + }; + + struct func_6param : public base_func + { + using exprtk::ifunction::operator(); + + func_6param() : base_func(6) {} + + inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3, v4, v5); + return this->value(base_func::expression); + } + }; + + static T return_value(expression_t& e) + { + typedef exprtk::results_context results_context_t; + typedef typename results_context_t::type_store_t type_t; + typedef typename type_t::scalar_view scalar_t; + + const T result = e.value(); + + if (e.return_invoked()) + { + // Due to the post compilation checks, it can be safely + // assumed that there will be at least one parameter + // and that the first parameter will always be scalar. + return scalar_t(e.results()[0])(); + } + + return result; + } + + #define def_fp_retval(N) \ + struct func_##N##param_retval : public func_##N##param \ + { \ + inline T value(expression_t& e) \ + { \ + return return_value(e); \ + } \ + }; \ + + def_fp_retval(0) + def_fp_retval(1) + def_fp_retval(2) + def_fp_retval(3) + def_fp_retval(4) + def_fp_retval(5) + def_fp_retval(6) + + template class Sequence> + inline bool add(const std::string& name, + const std::string& expression, + const Sequence& var_list, + const bool override = false) + { + const typename std::map::iterator itr = expr_map_.find(name); + + if (expr_map_.end() != itr) + { + if (!override) + { + exprtk_debug(("Compositor error(add): function '%s' already defined\n", + name.c_str())); + + return false; + } + + remove(name, var_list.size()); + } + + if (compile_expression(name, expression, var_list)) + { + const std::size_t n = var_list.size(); + + fp_map_[n][name]->setup(expr_map_[name]); + + return true; + } + else + { + exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", + name.c_str())); + + return false; + } + } + + public: + + function_compositor() + : parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return) + , fp_map_(7) + {} + + function_compositor(const symbol_table_t& st) + : symbol_table_(st) + , parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return) + , fp_map_(7) + {} + + ~function_compositor() + { + clear(); + } + + inline symbol_table_t& symbol_table() + { + return symbol_table_; + } + + inline const symbol_table_t& symbol_table() const + { + return symbol_table_; + } + + inline void add_auxiliary_symtab(symbol_table_t& symtab) + { + auxiliary_symtab_list_.push_back(&symtab); + } + + void clear() + { + symbol_table_.clear(); + expr_map_ .clear(); + + for (std::size_t i = 0; i < fp_map_.size(); ++i) + { + typename funcparam_t::iterator itr = fp_map_[i].begin(); + typename funcparam_t::iterator end = fp_map_[i].end (); + + while (itr != end) + { + delete itr->second; + ++itr; + } + + fp_map_[i].clear(); + } + } + + inline bool add(const function& f, const bool override = false) + { + return add(f.name_, f.expression_, f.v_,override); + } + + private: + + template class Sequence> + bool compile_expression(const std::string& name, + const std::string& expression, + const Sequence& input_var_list, + bool return_present = false) + { + expression_t compiled_expression; + symbol_table_t local_symbol_table; + + local_symbol_table.load_from(symbol_table_); + local_symbol_table.add_constants(); + + if (!valid(name,input_var_list.size())) + return false; + + if (!forward(name, + input_var_list.size(), + local_symbol_table, + return_present)) + return false; + + compiled_expression.register_symbol_table(local_symbol_table); + + for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) + { + compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); + } + + std::string mod_expression; + + for (std::size_t i = 0; i < input_var_list.size(); ++i) + { + mod_expression += " var " + input_var_list[i] + "{};\n"; + } + + if ( + ('{' == details::front(expression)) && + ('}' == details::back (expression)) + ) + mod_expression += "~" + expression + ";"; + else + mod_expression += "~{" + expression + "};"; + + if (!parser_.compile(mod_expression,compiled_expression)) + { + exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); + exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + + if (!return_present && parser_.dec().return_present()) + { + remove(name,input_var_list.size()); + + return compile_expression(name, expression, input_var_list, true); + } + + // Make sure every return point has a scalar as its first parameter + if (parser_.dec().return_present()) + { + typedef std::vector str_list_t; + + str_list_t ret_param_list = parser_.dec().return_param_type_list(); + + for (std::size_t i = 0; i < ret_param_list.size(); ++i) + { + const std::string& params = ret_param_list[i]; + + if (params.empty() || ('T' != params[0])) + { + exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", + name.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + } + } + + expr_map_[name] = compiled_expression; + + exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); + + if (symbol_table_.add_function(name,ifunc)) + return true; + else + { + exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", + name.c_str())); + return false; + } + } + + inline bool symbol_used(const std::string& symbol) const + { + return ( + symbol_table_.is_variable (symbol) || + symbol_table_.is_stringvar (symbol) || + symbol_table_.is_function (symbol) || + symbol_table_.is_vector (symbol) || + symbol_table_.is_vararg_function(symbol) + ); + } + + inline bool valid(const std::string& name, + const std::size_t& arg_count) const + { + if (arg_count > 6) + return false; + else if (symbol_used(name)) + return false; + else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) + return false; + else + return true; + } + + inline bool forward(const std::string& name, + const std::size_t& arg_count, + symbol_table_t& sym_table, + const bool ret_present = false) + { + switch (arg_count) + { + #define case_stmt(N) \ + case N : (fp_map_[arg_count])[name] = \ + (!ret_present) ? static_cast \ + (new func_##N##param) : \ + static_cast \ + (new func_##N##param_retval) ; \ + break; \ + + case_stmt(0) case_stmt(1) case_stmt(2) + case_stmt(3) case_stmt(4) case_stmt(5) + case_stmt(6) + #undef case_stmt + } + + exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); + + return sym_table.add_function(name,ifunc); + } + + inline void remove(const std::string& name, const std::size_t& arg_count) + { + if (arg_count > 6) + return; + + const typename std::map::iterator em_itr = expr_map_.find(name); + + if (expr_map_.end() != em_itr) + { + expr_map_.erase(em_itr); + } + + const typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); + + if (fp_map_[arg_count].end() != fp_itr) + { + delete fp_itr->second; + fp_map_[arg_count].erase(fp_itr); + } + + symbol_table_.remove_function(name); + } + + private: + + symbol_table_t symbol_table_; + parser_t parser_; + std::map expr_map_; + std::vector fp_map_; + std::vector auxiliary_symtab_list_; + }; // class function_compositor + + template + inline bool pgo_primer() + { + static const std::string expression_list[] = + { + "(y + x)", + "2 * (y + x)", + "(2 * y + 2 * x)", + "(y + x / y) * (x - y / x)", + "x / ((x + y) * (x - y)) / y", + "1 - ((x * y) + (y / x)) - 3", + "sin(2 * x) + cos(pi / y)", + "1 - sin(2 * x) + cos(pi / y)", + "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", + "(x^2 / sin(2 * pi / y)) -x / 2", + "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", + "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", + "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", + "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", + "(yy + xx)", + "2 * (yy + xx)", + "(2 * yy + 2 * xx)", + "(yy + xx / yy) * (xx - yy / xx)", + "xx / ((xx + yy) * (xx - yy)) / yy", + "1 - ((xx * yy) + (yy / xx)) - 3", + "sin(2 * xx) + cos(pi / yy)", + "1 - sin(2 * xx) + cos(pi / yy)", + "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", + "(xx^2 / sin(2 * pi / yy)) -xx / 2", + "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", + "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", + "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", + "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", + "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", + "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", + "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", + "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", + "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", + "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", + "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", + "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", + "2 + (x * (y / 3))", "x + (2 * (3 / y))", + "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", + "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", + "x + ((2 * 3) / y)", "(((x + y) * z) / w)", + "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", + "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", + "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", + "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", + "((x + (2 * 3)) / y)", + "(xx + yy) * zz", "xx + (yy * zz)", + "(xx + yy) * 7", "xx + (yy * 7)", + "(xx + 7) * yy", "xx + (7 * yy)", + "(7 + xx) * yy", "7 + (xx * yy)", + "(2 + x) * 3", "2 + (x * 3)", + "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", + "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", + "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", + "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", + "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", + "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", + "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", + "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", + "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", + "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", + "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", + "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", + "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", + "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", + "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", + "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", + "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", + "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", + "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", + "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", + "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", + "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", + "((xx + (2 * 3)) / yy)" + }; + + static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); + + T x = T(0); + T y = T(0); + T z = T(0); + T w = T(0); + T xx = T(0); + T yy = T(0); + T zz = T(0); + T ww = T(0); + + exprtk::symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable( "x", x); + symbol_table.add_variable( "y", y); + symbol_table.add_variable( "z", z); + symbol_table.add_variable( "w", w); + symbol_table.add_variable("xx",xx); + symbol_table.add_variable("yy",yy); + symbol_table.add_variable("zz",zz); + symbol_table.add_variable("ww",ww); + + typedef typename std::deque > expr_list_t; + expr_list_t expr_list; + + const std::size_t rounds = 50; + + { + for (std::size_t r = 0; r < rounds; ++r) + { + expr_list.clear(); + exprtk::parser parser; + + for (std::size_t i = 0; i < expression_list_size; ++i) + { + exprtk::expression expression; + expression.register_symbol_table(symbol_table); + + if (!parser.compile(expression_list[i],expression)) + { + return false; + } + + expr_list.push_back(expression); + } + } + } + + struct execute + { + static inline T process(T& x, T& y, expression& expression) + { + static const T lower_bound = T(-20); + static const T upper_bound = T(+20); + static const T delta = T(0.1); + + T total = T(0); + + for (x = lower_bound; x <= upper_bound; x += delta) + { + for (y = lower_bound; y <= upper_bound; y += delta) + { + total += expression.value(); + } + } + + return total; + } + }; + + for (std::size_t i = 0; i < expr_list.size(); ++i) + { + execute::process( x, y, expr_list[i]); + execute::process(xx, yy, expr_list[i]); + } + + { + for (std::size_t i = 0; i < 10000; ++i) + { + const T v = T(123.456 + i); + + if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(1))))) + return false; + + #define else_stmt(N) \ + else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(N))))) \ + return false; \ + + else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) + else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) + else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) + else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) + else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) + else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) + else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) + else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) + else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) + else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) + else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) + else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) + else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) + else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) + else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61) + } + } + + return true; + } +} + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#else +# include +# include +# include +#endif + +namespace exprtk +{ + class timer + { + public: + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + timer() + : in_use_(false) + { + QueryPerformanceFrequency(&clock_frequency_); + } + + inline void start() + { + in_use_ = true; + QueryPerformanceCounter(&start_time_); + } + + inline void stop() + { + QueryPerformanceCounter(&stop_time_); + in_use_ = false; + } + + inline double time() const + { + return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); + } + + #else + + timer() + : in_use_(false) + { + start_time_.tv_sec = 0; + start_time_.tv_usec = 0; + + stop_time_.tv_sec = 0; + stop_time_.tv_usec = 0; + } + + inline void start() + { + in_use_ = true; + gettimeofday(&start_time_,0); + } + + inline void stop() + { + gettimeofday(&stop_time_, 0); + in_use_ = false; + } + + inline unsigned long long int usec_time() const + { + if (!in_use_) + { + if (stop_time_.tv_sec >= start_time_.tv_sec) + { + return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + + static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; + } + else + return std::numeric_limits::max(); + } + else + return std::numeric_limits::max(); + } + + inline double time() const + { + return usec_time() * 0.000001; + } + + #endif + + inline bool in_use() const + { + return in_use_; + } + + private: + + bool in_use_; + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + LARGE_INTEGER start_time_; + LARGE_INTEGER stop_time_; + LARGE_INTEGER clock_frequency_; + #else + struct timeval start_time_; + struct timeval stop_time_; + #endif + }; + + template + struct type_defs + { + typedef symbol_table symbol_table_t; + typedef expression expression_t; + typedef parser parser_t; + typedef parser_error::type error_t; + typedef function_compositor compositor_t; + typedef typename compositor_t::function function_t; + }; + +} // namespace exprtk + +#ifndef exprtk_disable_rtl_io +namespace exprtk +{ + namespace rtl { namespace io { namespace details + { + template + inline void print_type(const std::string& fmt, + const T v, + exprtk::details::numeric::details::real_type_tag) + { + printf(fmt.c_str(),v); + } + + template + struct print_impl + { + typedef typename igeneric_function::generic_type generic_type; + typedef typename igeneric_function::parameter_list_t parameter_list_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + typedef typename generic_type::string_view string_t; + typedef typename exprtk::details::numeric::details::number_type::type num_type; + + static void process(const std::string& scalar_format, parameter_list_t parameters) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + switch (gt.type) + { + case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); + break; + + case generic_type::e_vector : print(scalar_format,vector_t(gt)); + break; + + case generic_type::e_string : print(string_t(gt)); + break; + + default : continue; + } + } + } + + static inline void print(const std::string& scalar_format, const scalar_t& s) + { + print_type(scalar_format,s(),num_type()); + } + + static inline void print(const std::string& scalar_format, const vector_t& v) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + print_type(scalar_format,v[i],num_type()); + + if ((i + 1) < v.size()) + printf(" "); + } + } + + static inline void print(const string_t& s) + { + printf("%s",to_str(s).c_str()); + } + }; + + } // namespace exprtk::rtl::io::details + + template + struct print : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + print(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator() (parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct println : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + println(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator() (parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + printf("\n"); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct package + { + print p; + println pl; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("print" , p ) + exprtk_register_function("println", pl) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_io_file +#include +namespace exprtk +{ + namespace rtl { namespace io { namespace file { namespace details + { + enum file_mode + { + e_error = 0, + e_read = 1, + e_write = 2, + e_rdwrt = 4 + }; + + struct file_descriptor + { + file_descriptor(const std::string& fname, const std::string& access) + : stream_ptr(0) + , mode(get_file_mode(access)) + , file_name(fname) + {} + + void* stream_ptr; + file_mode mode; + std::string file_name; + + bool open() + { + if (e_read == mode) + { + std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else if (e_write == mode) + { + std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else if (e_rdwrt == mode) + { + std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else + return false; + } + + template + void close(Ptr& p) + { + Stream* stream = reinterpret_cast(p); + stream->close(); + delete stream; + p = reinterpret_cast(0); + } + + bool close() + { + switch (mode) + { + case e_read : close(stream_ptr); + break; + + case e_write : close(stream_ptr); + break; + + case e_rdwrt : close (stream_ptr); + break; + + default : return false; + } + + return true; + } + + template + bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_write : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + template + bool read(View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_read : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + bool getline(std::string& s) + { + switch (mode) + { + case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + default : return false; + } + } + + bool eof() const + { + switch (mode) + { + case e_read : return reinterpret_cast(stream_ptr)->eof(); + case e_write : return reinterpret_cast(stream_ptr)->eof(); + case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); + default : return true; + } + } + + file_mode get_file_mode(const std::string& access) const + { + if (access.empty() || access.size() > 2) + return e_error; + + std::size_t w_cnt = 0; + std::size_t r_cnt = 0; + + for (std::size_t i = 0; i < access.size(); ++i) + { + switch (std::tolower(access[i])) + { + case 'r' : r_cnt++; break; + case 'w' : w_cnt++; break; + default : return e_error; + } + } + + if ((0 == r_cnt) && (0 == w_cnt)) + return e_error; + else if ((r_cnt > 1) || (w_cnt > 1)) + return e_error; + else if ((1 == r_cnt) && (1 == w_cnt)) + return e_rdwrt; + else if (1 == r_cnt) + return e_read; + else + return e_write; + } + }; + + template + file_descriptor* make_handle(T v) + { + details::file_descriptor* fd = reinterpret_cast(0); + + const std::size_t fd_size = sizeof(details::file_descriptor*); + + std::memcpy(reinterpret_cast(&fd), + reinterpret_cast(&v), + fd_size); + return fd; + } + + template + void perform_check() + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (sizeof(T) < sizeof(void*)) + { + throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + } // namespace exprtk::rtl::io::file::details + + template + class open : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + + using exprtk::igeneric_function::operator(); + + open() + : exprtk::igeneric_function("S|SS") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + std::string file_name = to_str(string_t(parameters[0])); + std::string access; + + if (file_name.empty()) + return T(0); + + if (0 == ps_index) + access = "r"; + else if (0 == string_t(parameters[1]).size()) + return T(0); + else + access = to_str(string_t(parameters[1])); + + details::file_descriptor* fd = new details::file_descriptor(file_name,access); + + if (fd->open()) + { + T t = T(0); + + const std::size_t fd_size = sizeof(details::file_descriptor*); + + std::memcpy(reinterpret_cast(&t ), + reinterpret_cast(&fd), + fd_size); + return t; + } + else + { + delete fd; + return T(0); + } + } + }; + + template + struct close : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + close() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator() (const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + if (!fd->close()) + return T(0); + + delete fd; + + return T(1); + } + }; + + template + class write : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + write() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + switch (ps_index) + { + case 0 : { + const string_t buffer(parameters[1]); + const std::size_t amount = buffer.size(); + return T(fd->write(buffer, amount) ? 1 : 0); + } + + case 1 : { + const string_t buffer(parameters[1]); + const std::size_t amount = + std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(buffer, amount) ? 1 : 0); + } + + case 2 : { + const vector_t vec(parameters[1]); + const std::size_t amount = vec.size(); + return T(fd->write(vec, amount) ? 1 : 0); + } + + case 3 : { + const vector_t vec(parameters[1]); + const std::size_t amount = + std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(vec, amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class read : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + read() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + const std::size_t amount = buffer.size(); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + const std::size_t amount = + std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 2 : { + vector_t vec(parameters[1]); + const std::size_t amount = vec.size(); + return T(fd->read(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + const std::size_t amount = + std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(vec,amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class getline : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + + using exprtk::igeneric_function::operator(); + + getline() + : igfun_t("T",igfun_t::e_rtrn_string) + { details::perform_check(); } + + inline T operator() (std::string& result, + parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + return T(fd->getline(result) ? 1 : 0); + } + }; + + template + struct eof : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + eof() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator() (const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + return (fd->eof() ? T(1) : T(0)); + } + }; + + template + struct package + { + open o; + close c; + write w; + read r; + getline g; + eof e; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::file::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("open" , o) + exprtk_register_function("close" , c) + exprtk_register_function("write" , w) + exprtk_register_function("read" , r) + exprtk_register_function("getline" , g) + exprtk_register_function("eof" , e) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io::file + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_vecops +namespace exprtk +{ + namespace rtl { namespace vecops { + + namespace helper + { + template + inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) + { + if (r0 > (v.size() - 1)) + return true; + else if (r1 > (v.size() - 1)) + return true; + else if (r1 < r0) + return true; + else + return false; + } + + template + struct load_vector_range + { + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + static inline bool process(parameter_list_t& parameters, + std::size_t& r0, std::size_t& r1, + const std::size_t& r0_prmidx, + const std::size_t& r1_prmidx, + const std::size_t vec_idx = 0) + { + if (r0_prmidx >= parameters.size()) + return false; + + if (r1_prmidx >= parameters.size()) + return false; + + if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) + return false; + + if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) + return false; + + return !invalid_range(vector_t(parameters[vec_idx]), r0, r1); + } + }; + } + + namespace details + { + template + inline void kahan_sum(T& sum, T& error, const T v) + { + const T x = v - error; + const T y = sum + x; + error = (y - sum) - x; + sum = y; + } + + } // namespace exprtk::rtl::details + + template + class all_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class all_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class any_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(1); + } + } + + return T(0); + } + }; + + template + class any_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) + { + return T(1); + } + } + + return T(0); + } + }; + + template + class count : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + count() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + std::size_t cnt = 0; + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) ++cnt; + } + + return T(cnt); + } + }; + + template + class copy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + copy() + : exprtk::igeneric_function("VV|VTTVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + vector_t y(parameters[(0 == ps_index) ? 1 : 3]); + + std::size_t xr0 = 0; + std::size_t xr1 = x.size() - 1; + + std::size_t yr0 = 0; + std::size_t yr1 = y.size() - 1; + + if (1 == ps_index) + { + if ( + !helper::load_vector_range::process(parameters, xr0, xr1, 1, 2, 0) || + !helper::load_vector_range::process(parameters, yr0, yr1, 4, 5, 3) + ) + return T(0); + } + + const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); + + std::copy( + x.begin() + xr0, + x.begin() + xr0 + n, + y.begin() + yr0); + + return T(n); + } + }; + + template + class rol : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + rol() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + const std::size_t shift = n % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class ror : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + ror() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + std::size_t dist = r1 - r0 + 1; + std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class shift_left : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_left() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + n, + vec.begin() + r1 + 1); + + for (std::size_t i = r1 - n + 1; i <= r1; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class shift_right : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_right() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + const std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + for (std::size_t i = r0; i < r0 + n; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class sort : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sort() + : exprtk::igeneric_function("V|VTT|VS|VSTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VS - vector, string + 3. VSTT - vector, string, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + return T(0); + if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return T(0); + + bool ascending = true; + + if ((2 == ps_index) || (3 == ps_index)) + { + if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) + ascending = true; + else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) + ascending = false; + else + return T(0); + } + + if (ascending) + std::sort( + vec.begin() + r0, + vec.begin() + r1 + 1, + std::less()); + else + std::sort( + vec.begin() + r0, + vec.begin() + r1 + 1, + std::greater()); + + return T(1); + } + }; + + template + class nthelement : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + nthelement() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, nth-element + 1. VTTT - vector, nth-element, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + + std::nth_element( + vec.begin() + r0, + vec.begin() + r0 + n , + vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class iota : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + iota() + : exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") + /* + Overloads: + 0. VT - vector, increment + 1. VTT - vector, increment, base + 2. VTTTT - vector, increment, r0, r1 + 3. VTTTT - vector, increment, base, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + T increment = scalar_t(parameters[1])(); + T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((2 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 0)) + return std::numeric_limits::quiet_NaN(); + else + { + long long j = 0; + + for (std::size_t i = r0; i <= r1; ++i, ++j) + { + vec[i] = base + (increment * j); + } + } + + return T(1); + } + }; + + template + class sumk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sumk() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + T error = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result, error, vec[i]); + } + + return result; + } + }; + + template + class axpy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpy() + : exprtk::igeneric_function("TVV|TVVTT") + /* + y <- ax + y + Overloads: + 0. TVV - a, x(vector), y(vector) + 1. TVVTT - a, x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t y(parameters[2]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + y[i]; + } + + return T(1); + } + }; + + template + class axpby : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpby() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + y <- ax + by + Overloads: + 0. TVTV - a, x(vector), b, y(vector) + 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t y(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpyz() + : exprtk::igeneric_function("TVVV|TVVVTT") + /* + z <- ax + y + Overloads: + 0. TVVV - a, x(vector), y(vector), z(vector) + 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + const vector_t y(parameters[2]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + y[i]; + } + + return T(1); + } + }; + + template + class axpbyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbyz() + : exprtk::igeneric_function("TVTVV|TVTVVTT") + /* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + const vector_t y(parameters[3]); + vector_t z(parameters[4]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpbz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbz() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + z <- ax + b + Overloads: + 0. TVTV - a, x(vector), b, z(vector) + 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = x.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + b; + } + + return T(1); + } + }; + + template + class dot : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dot() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + result += (x[i] * y[i]); + } + + return result; + } + }; + + template + class dotk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dotk() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + T error = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result, error, (x[i] * y[i])); + } + + return result; + } + }; + + template + struct package + { + all_true at; + all_false af; + any_true nt; + any_false nf; + count c; + copy cp; + rol rl; + ror rr; + shift_left sl; + shift_right sr; + sort st; + nthelement ne; + iota ia; + sumk sk; + axpy b1_axpy; + axpby b1_axpby; + axpyz b1_axpyz; + axpbyz b1_axpbyz; + axpbz b1_axpbz; + dot dt; + dotk dtk; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::vecops::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("all_true" , at ) + exprtk_register_function("all_false" , af ) + exprtk_register_function("any_true" , nt ) + exprtk_register_function("any_false" , nf ) + exprtk_register_function("count" , c ) + exprtk_register_function("copy" , cp ) + exprtk_register_function("rotate_left" , rl ) + exprtk_register_function("rol" , rl ) + exprtk_register_function("rotate_right" , rr ) + exprtk_register_function("ror" , rr ) + exprtk_register_function("shftl" , sl ) + exprtk_register_function("shftr" , sr ) + exprtk_register_function("sort" , st ) + exprtk_register_function("nth_element" , ne ) + exprtk_register_function("iota" , ia ) + exprtk_register_function("sumk" , sk ) + exprtk_register_function("axpy" , b1_axpy ) + exprtk_register_function("axpby" , b1_axpby ) + exprtk_register_function("axpyz" , b1_axpyz ) + exprtk_register_function("axpbyz" , b1_axpbyz) + exprtk_register_function("axpbz" , b1_axpbz ) + exprtk_register_function("dot" , dt ) + exprtk_register_function("dotk" , dtk ) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::vecops + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +namespace exprtk +{ + namespace information + { + static const char* library = "Mathematical Expression Toolkit"; + static const char* version = "2.7182818284590452353602874713526" + "624977572470936999595749669676277" + "240766303535475945713821785251664" + "274274663919320030599218174135966"; + static const char* date = "20220101"; + + static inline std::string data() + { + static const std::string info_str = std::string(library) + + std::string(" v") + std::string(version) + + std::string(" (") + date + std::string(")"); + return info_str; + } + + } // namespace information + + #ifdef exprtk_debug + #undef exprtk_debug + #endif + + #ifdef exprtk_error_location + #undef exprtk_error_location + #endif + + #ifdef exprtk_disable_fallthrough_begin + #undef exprtk_disable_fallthrough_begin + #endif + + #ifdef exprtk_disable_fallthrough_end + #undef exprtk_disable_fallthrough_end + #endif + + #ifdef exprtk_override + #undef exprtk_override + #endif + + #ifdef exprtk_final + #undef exprtk_final + #endif + + #ifdef exprtk_delete + #undef exprtk_delete + #endif + +} // namespace exprtk + +#endif diff --git a/server/src/main.cpp b/server/src/main.cpp index abc8ddc3..6a84f619 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -7,6 +7,7 @@ #include #include "server.h" #include "main.h" +#include "exprtk.hpp" #if defined(CONF_FAMILY_UNIX) #include @@ -246,18 +247,66 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage) return 1; } + void CMain::WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, - double time_10010, double time_189, double time_10086, int tcp, int udp, int process, int thread, - int64_t network_rx, int64_t network_tx, int64_t network_in, int64_t network_out, int memory_total, int memory_used, - int swap_total, int swap_used, int hdd_total, int hdd_used, int io_read, int io_write, int cpu, - int online4, int online6) + double time_10010, double time_189, double time_10086, double tcp, double udp, double process, double thread, + double network_rx, double network_tx, double network_in, double network_out, double memory_total, double memory_used, + double swap_total, double swap_used, double hdd_total, double hdd_used, double io_read, double io_write, double cpu, + double online4, double online6) { - printf("%f\t%f\t%f\n", load_1, load_5, load_15); - printf("%f\t%f\t%f\n", ping_10010, ping_189, ping_10086); - printf("%f\t%f\t%f\n", time_10010, time_189, time_10086); - printf("%d\t%d\t%d\t%d\t%ld\t%ld\t%ld\t%ld\t\n", tcp, udp, process, thread, network_rx, network_tx, network_in, network_out); - printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n", memory_total, memory_used, swap_total, swap_used, hdd_total, hdd_used, io_read, io_write); - printf("%d\t%d\t%d\t\n", cpu, online4, online6); + int ID = 0; + while (strcmp(Watchdog(ID)->m_aName, "NULL")) + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + const std::string expression_string = Watchdog(ID)->m_aRule; + + symbol_table_t symbol_table; + symbol_table.add_variable("load_1",load_1); + symbol_table.add_variable("load_5",load_5); + symbol_table.add_variable("load_15",load_15); + symbol_table.add_variable("ping_10010",ping_10010); + symbol_table.add_variable("ping_189",ping_189); + symbol_table.add_variable("ping_10086",ping_10086); + symbol_table.add_variable("time_10010",time_10010); + symbol_table.add_variable("time_189",time_189); + symbol_table.add_variable("time_10086",time_10086); + symbol_table.add_variable("tcp",tcp); + symbol_table.add_variable("udp",udp); + symbol_table.add_variable("process",process); + symbol_table.add_variable("thread",thread); + symbol_table.add_variable("network_rx",network_rx); + symbol_table.add_variable("network_tx",network_tx); + symbol_table.add_variable("network_in",network_in); + symbol_table.add_variable("network_out",network_out); + symbol_table.add_variable("memory_total",memory_total); + symbol_table.add_variable("memory_used",memory_used); + symbol_table.add_variable("swap_total",swap_total); + symbol_table.add_variable("swap_used",swap_used); + symbol_table.add_variable("hdd_total",hdd_total); + symbol_table.add_variable("hdd_used",hdd_used); + symbol_table.add_variable("io_read",io_read); + symbol_table.add_variable("io_write",io_write); + symbol_table.add_variable("cpu",cpu); + symbol_table.add_variable("online4",online4); + symbol_table.add_variable("online6",online6); + symbol_table.add_constants(); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + if (expression.value() > 0) + { + printf("name: %s\n", Watchdog(ID)->m_aName); + printf("debug \n"); + } + + ID++; + } } void CMain::JSONUpdateThread(void *pUser) @@ -454,6 +503,7 @@ int CMain::ReadConfig() ID++; } + str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); } // if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT diff --git a/server/src/main.h b/server/src/main.h index fef95c11..66e4ff87 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -107,10 +107,10 @@ class CMain CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } void WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, - double time_10010, double time_189, double time_10086, int tcp, int udp, int process, int thread, - int64_t network_rx, int64_t network_tx, int64_t network_in, int64_t network_out, - int memory_total, int memory_used,int swap_total, int swap_used, int hdd_total, - int hdd_used, int io_read, int io_write, int cpu,int online4, int online6); + double time_10010, double time_189, double time_10086, double tcp, double udp, double process, double thread, + double network_rx, double network_tx, double network_in, double network_out,double memory_total, + double memory_used,double swap_total, double swap_used, double hdd_total, + double hdd_used, double io_read, double io_write, double cpu,double online4, double online6); CClient *Client(int ClientID) { return &m_aClients[ClientID]; } CClient *ClientNet(int ClientNetID); From a1689acbf03ac2560df97c1c3dfd089fdbbb741c Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 12 Jul 2022 16:58:30 +0800 Subject: [PATCH 005/144] trigger msg for watchdog --- server/src/main.cpp | 22 ++++++++++++++++++---- server/src/main.h | 3 ++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 6a84f619..bb562705 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -97,6 +97,13 @@ void CMain::OnDelClient(int ClientNetID) { int ClientID = ClientNetToClient(ClientNetID); dbg_msg("main", "OnDelClient(ncid=%d, cid=%d)", ClientNetID, ClientID); + //copy offline message for watchdog + WatchdogMessage(ClientNetID, + 0, 0, 0, 0, 0, 0, + 0, 0, 0,0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0,0, 0, 0, + 0, 0, 0, 0); if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS) { Client(ClientID)->m_Connected = false; @@ -193,7 +200,8 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage) str_copy(pClient->m_Stats.m_aCustom, rStart["custom"].u.string.ptr, sizeof(pClient->m_Stats.m_aCustom)); //copy message for watchdog to analysis - WatchdogMessage(pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, + WatchdogMessage(ClientNetID, + pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086, pClient->m_Stats.m_tcpCount, pClient->m_Stats.m_udpCount, pClient->m_Stats.m_processCount, @@ -248,7 +256,7 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage) } -void CMain::WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, +void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, double time_10010, double time_189, double time_10086, double tcp, double udp, double process, double thread, double network_rx, double network_tx, double network_in, double network_out, double memory_total, double memory_used, double swap_total, double swap_used, double hdd_total, double hdd_used, double io_read, double io_write, double cpu, @@ -301,8 +309,14 @@ void CMain::WatchdogMessage(double load_1, double load_5, double load_15, double if (expression.value() > 0) { - printf("name: %s\n", Watchdog(ID)->m_aName); - printf("debug \n"); + int ClientID = ClientNetToClient(ClientNetID); + printf("node info: %s\n", Client(ClientID)->m_aUsername); + printf("node info: %s\n", Client(ClientID)->m_aName); + printf("node info: %s\n", Client(ClientID)->m_aType); + printf("node info: %s\n", Client(ClientID)->m_aHost); + printf("node info: %s\n\n", Client(ClientID)->m_aLocation); + printf("watchdog name: %s\n", Watchdog(ID)->m_aName); + printf("watchdog rule: %s\n", Watchdog(ID)->m_aRule); } ID++; diff --git a/server/src/main.h b/server/src/main.h index 66e4ff87..258c10c4 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -106,7 +106,8 @@ class CMain int Run(); CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } - void WatchdogMessage(double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, + void WatchdogMessage(int ClientNetID, + double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, double time_10010, double time_189, double time_10086, double tcp, double udp, double process, double thread, double network_rx, double network_tx, double network_in, double network_out,double memory_total, double memory_used,double swap_total, double swap_used, double hdd_total, From 7316dbdddbd39aac03667836850c145480885f94 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 13 Jul 2022 16:55:38 +0800 Subject: [PATCH 006/144] update --- server/src/main.cpp | 21 +++++++++++++-------- server/src/main.h | 9 +++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index bb562705..d0a1e22b 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -310,15 +310,19 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl if (expression.value() > 0) { int ClientID = ClientNetToClient(ClientNetID); - printf("node info: %s\n", Client(ClientID)->m_aUsername); - printf("node info: %s\n", Client(ClientID)->m_aName); - printf("node info: %s\n", Client(ClientID)->m_aType); - printf("node info: %s\n", Client(ClientID)->m_aHost); - printf("node info: %s\n\n", Client(ClientID)->m_aLocation); - printf("watchdog name: %s\n", Watchdog(ID)->m_aName); - printf("watchdog rule: %s\n", Watchdog(ID)->m_aRule); + time_t currentStamp = (long long)time(/*ago*/0); + if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > 1800) + { + Client(ClientID)->m_AlarmLastTime = currentStamp; + printf("node info: %s\n", Client(ClientID)->m_aUsername); + printf("node info: %s\n", Client(ClientID)->m_aName); + printf("node info: %s\n", Client(ClientID)->m_aType); + printf("node info: %s\n", Client(ClientID)->m_aHost); + printf("node info: %s\n\n", Client(ClientID)->m_aLocation); + printf("watchdog name: %s\n", Watchdog(ID)->m_aName); + printf("watchdog rule: %s\n", Watchdog(ID)->m_aRule); + } } - ID++; } } @@ -675,3 +679,4 @@ int main(int argc, const char *argv[]) return RetVal; } + diff --git a/server/src/main.h b/server/src/main.h index 258c10c4..90554062 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -38,10 +38,11 @@ class CMain char m_aPassword[128]; int m_aMonthStart; //track month network traffic. by: https://cpp.la - int64_t m_LastNetworkIN; - int64_t m_LastNetworkOUT; - int64 m_TimeConnected; - int64 m_LastUpdate; + int64_t m_LastNetworkIN; //restore month traffic info. + int64_t m_LastNetworkOUT; //restore month traffic info. + int64_t m_TimeConnected; + int64_t m_LastUpdate; + int64_t m_AlarmLastTime; //record last alarm time. struct CStats { From f70705d872fc8f2eefc80db6b2bfe9999d2185d8 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 13 Jul 2022 17:11:22 +0800 Subject: [PATCH 007/144] next add callback --- server/config.json | 4 ++++ server/src/main.cpp | 3 ++- server/src/main.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/server/config.json b/server/config.json index 256b1f3b..2ab3bd45 100644 --- a/server/config.json +++ b/server/config.json @@ -42,21 +42,25 @@ { "name": "cpu high warning", "rule": "cpu>90", + "interval": 600, "callback": "https://yourSMSurl" }, { "name": "memory high warning", "rule": "(memory_used/memory_total)*100>90", + "interval": 600, "callback": "https://yourSMSurl" }, { "name": "ipv4 offline warning", "rule": "online4=0", + "interval": 1800, "callback": "https://yourSMSurl" }, { "name": "you can parse an expression combining any known field", "rule": "(hdd_used/hdd_total)*100>95", + "interval": 1800, "callback": "https://yourSMSurl" } ] diff --git a/server/src/main.cpp b/server/src/main.cpp index d0a1e22b..02dcd75d 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -311,7 +311,7 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl { int ClientID = ClientNetToClient(ClientNetID); time_t currentStamp = (long long)time(/*ago*/0); - if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > 1800) + if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) { Client(ClientID)->m_AlarmLastTime = currentStamp; printf("node info: %s\n", Client(ClientID)->m_aUsername); @@ -517,6 +517,7 @@ int CMain::ReadConfig() str_copy(Watchdog(ID)->m_aName, jStart[i]["name"].u.string.ptr, sizeof(Watchdog(ID)->m_aName)); str_copy(Watchdog(ID)->m_aRule, jStart[i]["rule"].u.string.ptr, sizeof(Watchdog(ID)->m_aRule)); + Watchdog(ID)->m_aInterval = jStart[i]["interval"].u.integer; str_copy(Watchdog(ID)->m_aCallback, jStart[i]["callback"].u.string.ptr, sizeof(Watchdog(ID)->m_aCallback)); ID++; diff --git a/server/src/main.h b/server/src/main.h index 90554062..80df5473 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -86,6 +86,7 @@ class CMain struct CWatchDog{ char m_aName[128]; char m_aRule[128]; + int m_aInterval; char m_aCallback[128]; } m_aCWatchDogs[NET_MAX_CLIENTS]; From 2e62ffa593b7360b738f65b6be52200d28659a8e Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 15 Jul 2022 21:14:39 +0800 Subject: [PATCH 008/144] link libcurl static lib --- Dockerfile | 2 +- server/Makefile | 2 +- server/src/main.cpp | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e94f2341..e78162ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM debian:buster as builder MAINTAINER cppla https://cpp.la -RUN apt-get update -y && apt-get -y install gcc g++ make +RUN apt-get update -y && apt-get -y install gcc g++ make libcurl4-openssl-dev COPY . . diff --git a/server/Makefile b/server/Makefile index 3ca07ff6..1c777f03 100644 --- a/server/Makefile +++ b/server/Makefile @@ -26,7 +26,7 @@ $(ODIR)/%.o: $(SDIR)/%.cpp $(CXX) -c $(INC) $(CXXFLAGS) $< -o $@ $(OUT): $(OBJS) - $(CXX) $(LIBS) $^ -o $(OUT) + $(CXX) $(LIBS) $^ -o $(OUT) -lcurl .PHONY: clean diff --git a/server/src/main.cpp b/server/src/main.cpp index 02dcd75d..87f9afe2 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -8,6 +8,7 @@ #include "server.h" #include "main.h" #include "exprtk.hpp" +#include "curl/curl.h" #if defined(CONF_FAMILY_UNIX) #include @@ -321,6 +322,22 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl printf("node info: %s\n\n", Client(ClientID)->m_aLocation); printf("watchdog name: %s\n", Watchdog(ID)->m_aName); printf("watchdog rule: %s\n", Watchdog(ID)->m_aRule); + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://cpp.la"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl"); + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + curl_easy_cleanup(curl); + } + curl_global_cleanup(); } } ID++; From baae11de3bf2864528c960e5fb263768e5f08350 Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 15 Jul 2022 22:34:44 +0800 Subject: [PATCH 009/144] tg sms --- server/src/main.cpp | 23 +++++++++++++---------- server/src/main.h | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 87f9afe2..5a819a21 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -315,22 +315,25 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) { Client(ClientID)->m_AlarmLastTime = currentStamp; - printf("node info: %s\n", Client(ClientID)->m_aUsername); - printf("node info: %s\n", Client(ClientID)->m_aName); - printf("node info: %s\n", Client(ClientID)->m_aType); - printf("node info: %s\n", Client(ClientID)->m_aHost); - printf("node info: %s\n\n", Client(ClientID)->m_aLocation); - printf("watchdog name: %s\n", Watchdog(ID)->m_aName); - printf("watchdog rule: %s\n", Watchdog(ID)->m_aRule); CURL *curl; CURLcode res; - + //todo 这里需要换乘线程 curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, "https://cpp.la"); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl"); + char urlBuffer[2048] = { 0 }; + sprintf(urlBuffer, "%s %%0A【告警名称】 %s %%0A【告警规则】 %s %%0A ---------------- %%0A【用户名】 %s %%0A【节点名】 %s %%0A【虚拟化】 %s %%0A【主机名】 %s %%0A【位 置】 %s", + Watchdog(ID)->m_aCallback, + Watchdog(ID)->m_aName, + Watchdog(ID)->m_aRule, + Client(ClientID)->m_aUsername, + Client(ClientID)->m_aName, + Client(ClientID)->m_aType, + Client(ClientID)->m_aHost, + Client(ClientID)->m_aLocation); + curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); + //curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "todo=nihao"); res = curl_easy_perform(curl); if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", diff --git a/server/src/main.h b/server/src/main.h index 80df5473..5070743e 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -87,7 +87,7 @@ class CMain char m_aName[128]; char m_aRule[128]; int m_aInterval; - char m_aCallback[128]; + char m_aCallback[1024]; } m_aCWatchDogs[NET_MAX_CLIENTS]; struct CJSONUpdateThreadData From 2ead43a0d890ee46f76efb0d61b986cc978449f9 Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 15 Jul 2022 23:14:53 +0800 Subject: [PATCH 010/144] update --- server/src/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 5a819a21..4978da24 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -314,19 +314,23 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl time_t currentStamp = (long long)time(/*ago*/0); if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) { + //todo 这里需要换成线程 Client(ClientID)->m_AlarmLastTime = currentStamp; CURL *curl; CURLcode res; - //todo 这里需要换乘线程 curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if(curl) { + char standardTime[32]= { 0 }; + strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(¤tStamp)); + char urlBuffer[2048] = { 0 }; - sprintf(urlBuffer, "%s %%0A【告警名称】 %s %%0A【告警规则】 %s %%0A ---------------- %%0A【用户名】 %s %%0A【节点名】 %s %%0A【虚拟化】 %s %%0A【主机名】 %s %%0A【位 置】 %s", + sprintf(urlBuffer, "%s %%0A【告警名称】 %s %%0A【告警规则】 %s %%0A【告警时间】 %s %%0A ---------------- %%0A【用户名】 %s %%0A【节点名】 %s %%0A【虚拟化】 %s %%0A【主机名】 %s %%0A【位 置】 %s", Watchdog(ID)->m_aCallback, Watchdog(ID)->m_aName, Watchdog(ID)->m_aRule, + standardTime, Client(ClientID)->m_aUsername, Client(ClientID)->m_aName, Client(ClientID)->m_aType, From 135eb180c8bf810c2a41f49033d27a731f2b9ab2 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 00:32:33 +0800 Subject: [PATCH 011/144] escape --- server/src/main.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 4978da24..40f5dc81 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -322,12 +322,13 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl curl = curl_easy_init(); if(curl) { + //standard time char standardTime[32]= { 0 }; strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(¤tStamp)); - char urlBuffer[2048] = { 0 }; - sprintf(urlBuffer, "%s %%0A【告警名称】 %s %%0A【告警规则】 %s %%0A【告警时间】 %s %%0A ---------------- %%0A【用户名】 %s %%0A【节点名】 %s %%0A【虚拟化】 %s %%0A【主机名】 %s %%0A【位 置】 %s", - Watchdog(ID)->m_aCallback, + //url encode + char encodeBuffer[2048] = { 0 }; + sprintf(encodeBuffer, " \n【告警名称】 %s \n【告警规则】 %s \n【告警时间】 %s \n ---------------- \n【用户名】 %s \n【节点名】 %s \n【虚拟化】 %s \n【主机名】 %s \n【位 置】 %s", Watchdog(ID)->m_aName, Watchdog(ID)->m_aRule, standardTime, @@ -336,12 +337,19 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl Client(ClientID)->m_aType, Client(ClientID)->m_aHost, Client(ClientID)->m_aLocation); + char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer)); + + //standard url + char urlBuffer[2048] = { 0 }; + sprintf(urlBuffer, "%s%s",Watchdog(ID)->m_aCallback, encodeUrl); + + curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); - //curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "todo=nihao"); res = curl_easy_perform(curl); if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + if(encodeUrl) + curl_free(encodeUrl); curl_easy_cleanup(curl); } curl_global_cleanup(); From 022e5edb282935e0b7064311e3d36cbf69753934 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 00:41:25 +0800 Subject: [PATCH 012/144] formate --- server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 40f5dc81..f9e40fad 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -328,7 +328,7 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl //url encode char encodeBuffer[2048] = { 0 }; - sprintf(encodeBuffer, " \n【告警名称】 %s \n【告警规则】 %s \n【告警时间】 %s \n ---------------- \n【用户名】 %s \n【节点名】 %s \n【虚拟化】 %s \n【主机名】 %s \n【位 置】 %s", + sprintf(encodeBuffer, " \n\n【告警名称】 %s \n\n【告警规则】 %s \n\n【告警时间】 %s \n\n ---------------- \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", Watchdog(ID)->m_aName, Watchdog(ID)->m_aRule, standardTime, From 27039932722489e33ceb9b416d3b57176b804536 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 13:45:37 +0800 Subject: [PATCH 013/144] add timeout for libcurl --- server/src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/main.cpp b/server/src/main.cpp index f9e40fad..62a42178 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -345,6 +345,8 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); res = curl_easy_perform(curl); if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); From 6151806141a8133f72b9b8bcd39ed09e29b727ff Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 14:42:32 +0800 Subject: [PATCH 014/144] c++ eval build use c++11 --- README.md | 30 ++++++++++-------------------- server/Makefile | 2 +- server/src/main.cpp | 2 +- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0cced3a4..c7d061a3 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,10 @@ git clone https://github.com/cppla/ServerStatus.git 一、生成服务端程序 ``` -cd ServerStatus/server -make +`Debian/Ubuntu`: apt-get -y install gcc g++ make libcurl4-openssl-dev +`Centos/Redhat`: yum -y install gcc gcc-c++ make libcurl-devel + +cd ServerStatus/server && make ./sergate ``` 如果没错误提示,OK,ctrl+c关闭;如果有错误提示,检查35601端口是否被占用 @@ -100,26 +102,14 @@ web-dir参数为上一步设置的网站根目录,务必修改成自己网站 2、python3 client-linux.py 运行即可。 二、client-psutil版配置: -1、安装psutil跨平台依赖库 -2、vim client-psutil.py, 修改SERVER地址,username帐号, password密码 -3、python3 client-psutil.py 运行即可。 +1、安装psutil跨平台依赖库 ``` -### for Centos: -sudo yum -y install epel-release -sudo yum -y install python3-pip -sudo yum clean all -sudo yum -y install gcc -sudo yum -y install python3-devel -sudo pip3 install psutil - -### for Ubuntu/Debian: -sudo apt -y install python3-pip -sudo pip3 install psutil - -### for Windows: -地址:https://pypi.org/project/psutil/ -下载psutil for windows, 安装即可 +`Debian/Ubuntu`: apt -y install python3-pip && pip3 install psutil +`Centos/Redhat`: yum -y install python3-pip gcc python3-devel && pip3 install psutil +`Windows`: https://pypi.org/project/psutil/ ``` +2、vim client-psutil.py, 修改SERVER地址,username帐号, password密码 +3、python3 client-psutil.py 运行即可。 打开云探针页面,就可以正常的监控。接下来把服务器和客户端脚本自行加入开机启动,或者进程守护,或以后台方式运行即可!例如: nohup python3 client-linux.py & diff --git a/server/Makefile b/server/Makefile index 1c777f03..ccee6fbf 100644 --- a/server/Makefile +++ b/server/Makefile @@ -6,7 +6,7 @@ CFLAGS = -Wall -O2 #CXX = clang++ CXX = g++ -CXXFLAGS = -Wall -O2 +CXXFLAGS = -Wall -O2 -std=c++11 ODIR = obj SDIR = src diff --git a/server/src/main.cpp b/server/src/main.cpp index 62a42178..1dd7981d 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -349,7 +349,7 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); res = curl_easy_perform(curl); if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + fprintf(stderr, "watchdog failed: %s\n", curl_easy_strerror(res)); if(encodeUrl) curl_free(encodeUrl); curl_easy_cleanup(curl); From b03d090a5c607a1f60af777d9b5aa6c6b1283550 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 17:47:57 +0800 Subject: [PATCH 015/144] update readme --- README.md | 59 ++++++++++++++++++++++++++++++++-------------- server/config.json | 4 ++-- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c7d061a3..ee4b5e29 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,10 @@ [![Python Support](https://img.shields.io/badge/python-2.7%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) [![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus) [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) -[![Version](https://img.shields.io/badge/Version-Beta%201.0.8-red)](https://github.com/cppla/ServerStatus) +[![Version](https://img.shields.io/badge/Version-Beta%201.0.9-red)](https://github.com/cppla/ServerStatus) ![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) -`curl -sSL https://get.docker.com/ | sh && apt -y install docker-compose` - # 目录介绍: * clients 客户端文件 @@ -26,15 +24,12 @@ 【服务端】: ```bash -`OneTouch`: +`Docker`: wget --no-check-certificate -qO ~/serverstatus-config.json https://raw.githubusercontent.com/cppla/ServerStatus/master/server/config.json && mkdir ~/serverstatus-monthtraffic docker run -d --restart=always --name=serverstatus -v ~/serverstatus-config.json:/ServerStatus/server/config.json -v ~/serverstatus-monthtraffic:/usr/share/nginx/html/json -p 80:80 -p 35601:35601 cppla/serverstatus:latest -`ServerStatus`: docker-compose up -d - -`ServerStatus with tgbot`: TG_CHAT_ID=你的电报ID TG_BOT_TOKEN=你的电报密钥 docker-compose -f docker-compose-telegram.yml up -d - +`Docker-compose`: docker-compose up -d ``` 【客户端】: @@ -52,9 +47,9 @@ wget --no-check-certificate -qO client-linux.py 'https://raw.githubusercontent.c git clone https://github.com/cppla/ServerStatus.git ``` -【服务端配置】: +###【服务端配置】: -一、生成服务端程序 +#### 一、生成服务端程序 ``` `Debian/Ubuntu`: apt-get -y install gcc g++ make libcurl4-openssl-dev `Centos/Redhat`: yum -y install gcc gcc-c++ make libcurl-devel @@ -64,10 +59,11 @@ cd ServerStatus/server && make ``` 如果没错误提示,OK,ctrl+c关闭;如果有错误提示,检查35601端口是否被占用 -二、修改配置文件 -修改config.json文件,注意username, password的值需要和客户端对应一致     +#### 二、修改配置文件 +修改config.json文件,注意username, password的值需要和客户端对应一致。watchdog规则可以为任何已知字段的表达式     ``` -{"servers": +{ + "servers": [ { "username": "s01", @@ -78,30 +74,57 @@ cd ServerStatus/server && make "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 }, + ], + "watchdog": + [ + { + "name": "cpu高负载告警", + "rule": "cpu>90", + "interval": 1200, + "callback": "https://yourSMSurl" + }, + { + "name": "内存高负载告警", + "rule": "(memory_used/memory_total)*100>95", + "interval": 600, + "callback": "https://yourSMSurl" + }, + { + "name": "ipv4宕机告警", + "rule": "online4=0", + "interval": 1800, + "callback": "https://yourSMSurl" + }, + { + "name": "你可以组合任何已知字段的表达式", + "rule": "(hdd_used/hdd_total)*100>95", + "interval": 1800, + "callback": "https://yourSMSurl" + } ] } ``` -三、拷贝ServerStatus/status到你的网站目录 +#### 三、拷贝ServerStatus/status到你的网站目录 例如: ``` sudo cp -r ServerStatus/web/* /home/wwwroot/default ``` -四、运行服务端: +#### 四、运行服务端: web-dir参数为上一步设置的网站根目录,务必修改成自己网站的路径 ``` ./sergate --config=config.json --web-dir=/home/wwwroot/default ``` -【客户端配置】: +###【客户端配置】: 客户端有两个版本,client-linux为普通linux,client-psutil为跨平台版,普通版不成功,换成跨平台版即可。 -一、client-linux版配置: +#### 一、client-linux版配置: 1、vim client-linux.py, 修改SERVER地址,username帐号, password密码 2、python3 client-linux.py 运行即可。 -二、client-psutil版配置: +#### 二、client-psutil版配置: 1、安装psutil跨平台依赖库 ``` `Debian/Ubuntu`: apt -y install python3-pip && pip3 install psutil diff --git a/server/config.json b/server/config.json index 2ab3bd45..22472adc 100644 --- a/server/config.json +++ b/server/config.json @@ -42,12 +42,12 @@ { "name": "cpu high warning", "rule": "cpu>90", - "interval": 600, + "interval": 1200, "callback": "https://yourSMSurl" }, { "name": "memory high warning", - "rule": "(memory_used/memory_total)*100>90", + "rule": "(memory_used/memory_total)*100>95", "interval": 600, "callback": "https://yourSMSurl" }, From 32d302580e808cf0ef2484966f0e6327e557320f Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 17:53:17 +0800 Subject: [PATCH 016/144] update --- README.md | 20 ++++---------------- server/config.json | 2 +- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ee4b5e29..2ea61429 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ wget --no-check-certificate -qO client-linux.py 'https://raw.githubusercontent.c git clone https://github.com/cppla/ServerStatus.git ``` -###【服务端配置】: +##【服务端配置】: #### 一、生成服务端程序 ``` @@ -78,23 +78,11 @@ cd ServerStatus/server && make "watchdog": [ { - "name": "cpu高负载告警", - "rule": "cpu>90", + "name": "服务器负载高监控", + "rule": "load_5>10", "interval": 1200, "callback": "https://yourSMSurl" }, - { - "name": "内存高负载告警", - "rule": "(memory_used/memory_total)*100>95", - "interval": 600, - "callback": "https://yourSMSurl" - }, - { - "name": "ipv4宕机告警", - "rule": "online4=0", - "interval": 1800, - "callback": "https://yourSMSurl" - }, { "name": "你可以组合任何已知字段的表达式", "rule": "(hdd_used/hdd_total)*100>95", @@ -117,7 +105,7 @@ web-dir参数为上一步设置的网站根目录,务必修改成自己网站 ./sergate --config=config.json --web-dir=/home/wwwroot/default ``` -###【客户端配置】: +##【客户端配置】: 客户端有两个版本,client-linux为普通linux,client-psutil为跨平台版,普通版不成功,换成跨平台版即可。 #### 一、client-linux版配置: diff --git a/server/config.json b/server/config.json index 22472adc..5cbe02c8 100644 --- a/server/config.json +++ b/server/config.json @@ -59,7 +59,7 @@ }, { "name": "you can parse an expression combining any known field", - "rule": "(hdd_used/hdd_total)*100>95", + "rule": "load_5>10", "interval": 1800, "callback": "https://yourSMSurl" } From c5eed8e4fa942166655a81d8e377522b049156ff Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 18:00:10 +0800 Subject: [PATCH 017/144] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 加入watchdog 说明 --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2ea61429..675f4248 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,7 @@ wget --no-check-certificate -qO client-linux.py 'https://raw.githubusercontent.c # 手动安装教程: -【克隆代码】: -``` -git clone https://github.com/cppla/ServerStatus.git -``` - -##【服务端配置】: +**【服务端配置】** #### 一、生成服务端程序 ``` @@ -105,7 +100,8 @@ web-dir参数为上一步设置的网站根目录,务必修改成自己网站 ./sergate --config=config.json --web-dir=/home/wwwroot/default ``` -##【客户端配置】: +**【客户端配置】** + 客户端有两个版本,client-linux为普通linux,client-psutil为跨平台版,普通版不成功,换成跨平台版即可。 #### 一、client-linux版配置: @@ -122,7 +118,7 @@ web-dir参数为上一步设置的网站根目录,务必修改成自己网站 2、vim client-psutil.py, 修改SERVER地址,username帐号, password密码 3、python3 client-psutil.py 运行即可。 -打开云探针页面,就可以正常的监控。接下来把服务器和客户端脚本自行加入开机启动,或者进程守护,或以后台方式运行即可!例如: nohup python3 client-linux.py & +服务器和客户端自行加入开机启动,或进程守护,或后台方式运行。 例如: nohup python3 client-linux.py & `extra scene (run web/ssview.py)` ![Shell View](http://dl.cpp.la/Archive/serverstatus-shell.png) From a0fe8ee33cdc395c53cd2785bad75eabe6fd4b69 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 18:35:08 +0800 Subject: [PATCH 018/144] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit callback说明 --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 675f4248..e8cc5502 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,16 @@ cd ServerStatus/server && make 如果没错误提示,OK,ctrl+c关闭;如果有错误提示,检查35601端口是否被占用 #### 二、修改配置文件 -修改config.json文件,注意username, password的值需要和客户端对应一致。watchdog规则可以为任何已知字段的表达式     +```diff +! 修改config.json文件,注意username, password的值需要和客户端对应一致。 +! watchdog rule 可以为任何已知字段的表达式。 +! watchdog interval 最小通知间隔。 +! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= +! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= +! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= +! watchdog callback Email: todo +``` + ``` { "servers": From 9d706f4da8ac6cba1c3a1d9c30b32c9c497d1488 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 18:44:09 +0800 Subject: [PATCH 019/144] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update watchdog 说明 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8cc5502..c39adc93 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,8 @@ cd ServerStatus/server && make ! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= ! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= ! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= -! watchdog callback Email: todo +! watchdog callback WeChat: todo +! watchdog callback Email: todo ``` ``` From 522809483e4479e63b39e00b9cc41a5ac4a6c068 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 19:11:29 +0800 Subject: [PATCH 020/144] Compatible with older versions config.json --- server/src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 1dd7981d..46d4ac16 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -557,7 +557,8 @@ int CMain::ReadConfig() ID++; } str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); - } + } else + str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); // if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT // support by: https://cpp.la From 3eddb27d512fc0b5f526b78005da67de0d50bafa Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 19:30:29 +0800 Subject: [PATCH 021/144] update --- server/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config.json b/server/config.json index 5cbe02c8..0c76a94c 100644 --- a/server/config.json +++ b/server/config.json @@ -47,7 +47,7 @@ }, { "name": "memory high warning", - "rule": "(memory_used/memory_total)*100>95", + "rule": "(memory_used/memory_total)*100>90", "interval": 600, "callback": "https://yourSMSurl" }, From cbd803b6861bcbdc991c26898ab638db0255cbc7 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 19:46:59 +0800 Subject: [PATCH 022/144] Create README.md update tips --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c39adc93..79a8bec7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ ![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) +`Watchdog🐶告警已经加入,支持telegram·Server酱, PushDeer。 Next:WeChat, Email` + # 目录介绍: * clients 客户端文件 From ec16fc1facfd786844a78e8a82c34227118088d2 Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 16 Jul 2022 19:47:33 +0800 Subject: [PATCH 023/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79a8bec7..0a828353 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) -`Watchdog🐶告警已经加入,支持telegram·Server酱, PushDeer。 Next:WeChat, Email` +`Watchdog🐶告警已经加入,支持telegram, Server酱, PushDeer。 Next:WeChat, Email` # 目录介绍: From de0bc9dd74ebaf4340ea76521e44f30ec8e2cc6b Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 17 Jul 2022 10:08:04 +0800 Subject: [PATCH 024/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a828353..d350d898 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) -`Watchdog🐶告警已经加入,支持telegram, Server酱, PushDeer。 Next:WeChat, Email` +`Watchdog🐶已经加入,触发式告警。 interval只是为了防止频繁收到报警信息造成骚扰,并不是探测间隔。` # 目录介绍: From a788b5da90ea22a7d6f47eb5a8600ee3fc601ba1 Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 17 Jul 2022 10:11:11 +0800 Subject: [PATCH 025/144] . --- server/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/config.json b/server/config.json index 0c76a94c..da149473 100644 --- a/server/config.json +++ b/server/config.json @@ -41,8 +41,8 @@ "watchdog": [ { "name": "cpu high warning", - "rule": "cpu>90", - "interval": 1200, + "rule": "cpu>98", + "interval": 600, "callback": "https://yourSMSurl" }, { From 94896bac80f2cec98e4be03a73a40f35ea98b45b Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 18 Jul 2022 10:36:36 +0800 Subject: [PATCH 026/144] change docker to beijing time --- Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e78162ed..920a8fd8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,10 @@ RUN mkdir -p /ServerStatus/server/ COPY --from=builder server /ServerStatus/server/ COPY --from=builder web /usr/share/nginx/html/ +# china time +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + EXPOSE 80 35601 -CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html' \ No newline at end of file +CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html' From 615cec88c2cf53790c41d842727835542cedc5c9 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 21 Jul 2022 10:53:08 +0800 Subject: [PATCH 027/144] 300s --- server/config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/config.json b/server/config.json index da149473..cd64b149 100644 --- a/server/config.json +++ b/server/config.json @@ -52,9 +52,9 @@ "callback": "https://yourSMSurl" }, { - "name": "ipv4 offline warning", - "rule": "online4=0", - "interval": 1800, + "name": "offline warning", + "rule": "online4=0&online6=0", + "interval": 300, "callback": "https://yourSMSurl" }, { From 6ab6e16d0fdff0ff7cb182f518c671b5416274c5 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 1 Aug 2022 19:37:26 +0800 Subject: [PATCH 028/144] 1080 to 1200 --- web/css/dark.css | 2 +- web/css/light.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/css/dark.css b/web/css/dark.css index 2b70d380..255e24c9 100644 --- a/web/css/dark.css +++ b/web/css/dark.css @@ -22,7 +22,7 @@ tr.odd.expandRow > :hover { background: #212e36 !important; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } #ping { max-width: 95px; } -@media only screen and (max-width: 1080px) { +@media only screen and (max-width: 1200px) { #type, tr td:nth-child(4) { display:none; visibility:hidden; } #location, tr td:nth-child(5) { display:none; visibility:hidden; } #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } diff --git a/web/css/light.css b/web/css/light.css index abd2c98f..11a78a27 100644 --- a/web/css/light.css +++ b/web/css/light.css @@ -19,7 +19,7 @@ tr.odd.expandRow > :hover { background: #FFF !important; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } #ping { max-width: 95px; } -@media only screen and (max-width: 1080px) { +@media only screen and (max-width: 1200px) { #type, tr td:nth-child(4) { display:none; visibility:hidden; } #location, tr td:nth-child(5) { display:none; visibility:hidden; } #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } From bb5f03047ddeeb39d8e61c04c0c661746a1d9cd0 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Aug 2022 19:39:10 +0800 Subject: [PATCH 029/144] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d350d898..f621fcd3 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ cd ServerStatus/server && make [ { "name": "服务器负载高监控", - "rule": "load_5>10", - "interval": 1200, + "rule": "cpu>90&load_5>3", + "interval": 600, "callback": "https://yourSMSurl" }, { From c2259f347d50518197477292081728814b748700 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Aug 2022 19:39:54 +0800 Subject: [PATCH 030/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f621fcd3..a8731e1e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ cd ServerStatus/server && make ], "watchdog": [ - { + { "name": "服务器负载高监控", "rule": "cpu>90&load_5>3", "interval": 600, From b5edeea057b752e94fa5f3f8c7e60643908102a7 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 25 Aug 2022 14:40:56 +0800 Subject: [PATCH 031/144] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加一个邮箱服务 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8731e1e..4094f4a7 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,8 @@ cd ServerStatus/server && make ! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= ! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= ! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= -! watchdog callback WeChat: todo -! watchdog callback Email: todo +! watchdog callback Email【测试中, 10条/天】: https://api.cloudcpp.com/serverstatus?type=email&email=你自己的邮箱&content= +! watchdog callback WeChat: todo ``` ``` From 78c7da736100e1953b0502b0939a86b9b826d4f8 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 25 Aug 2022 16:03:46 +0800 Subject: [PATCH 032/144] =?UTF-8?q?=E7=BB=8F=E6=B5=8B=E8=AF=95=E9=82=AE?= =?UTF-8?q?=E7=AE=B1=20=E5=92=8Cwechat=E4=B8=8D=E8=83=BD=E7=A8=B3=E5=AE=9A?= =?UTF-8?q?=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 经测试邮箱 和wechat不能稳定发送 --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 4094f4a7..7271be2c 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,7 @@ cd ServerStatus/server && make ! watchdog interval 最小通知间隔。 ! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= ! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= -! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= -! watchdog callback Email【测试中, 10条/天】: https://api.cloudcpp.com/serverstatus?type=email&email=你自己的邮箱&content= -! watchdog callback WeChat: todo +! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= ``` ``` From 44656e565fb914b416b44d0d3f6f21df22c87cc2 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 25 Aug 2022 16:13:24 +0800 Subject: [PATCH 033/144] =?UTF-8?q?=E6=9B=B4=E6=94=B9watchdog=20callback?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更改watchdog callback说明 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7271be2c..f7d67140 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,13 @@ cd ServerStatus/server && make #### 二、修改配置文件 ```diff -! 修改config.json文件,注意username, password的值需要和客户端对应一致。 ! watchdog rule 可以为任何已知字段的表达式。 -! watchdog interval 最小通知间隔。 +! watchdog interval 最小通知间隔。 +! watchdog callback 可自定义为Get方法的URL,告警内容将拼接其后并发起回调。 + ! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= ! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= -! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= +! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text= ``` ``` From 10872059c5e4b17849572cf274ba2417c76fedff Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 25 Aug 2022 16:14:46 +0800 Subject: [PATCH 034/144] build 1.0.9 build 1.0.9 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f7d67140..361b30a8 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ * ServerStatus中文版是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。 * 在线演示:https://tz.cloudcpp.com -[![Python Support](https://img.shields.io/badge/python-2.7%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) +[![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) [![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus) [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) -[![Version](https://img.shields.io/badge/Version-Beta%201.0.9-red)](https://github.com/cppla/ServerStatus) +[![Version](https://img.shields.io/badge/Version-Build%201.0.9-red)](https://github.com/cppla/ServerStatus) ![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) From d5a047c78114861b72d0d6401ee806cc8449ccbf Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 25 Aug 2022 16:23:02 +0800 Subject: [PATCH 035/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 361b30a8..459e5659 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) [![Version](https://img.shields.io/badge/Version-Build%201.0.9-red)](https://github.com/cppla/ServerStatus) -![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png) +![Latest Version](http://dl.cpp.la/Archive/serverstatus_1.0.9.png) `Watchdog🐶已经加入,触发式告警。 interval只是为了防止频繁收到报警信息造成骚扰,并不是探测间隔。` From 35de279e89771ff6e0a72c37cfb2913ab2bd9613 Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 26 Aug 2022 14:53:47 +0800 Subject: [PATCH 036/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 459e5659..6136c36d 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ cd ServerStatus/server && make ``` { - "servers": + "servers": [ { "username": "s01", From 19d6a5ea8be2768e02a15295acc977fd3b165e68 Mon Sep 17 00:00:00 2001 From: c9cu <172232502@qq.com> Date: Sat, 29 Oct 2022 19:07:33 +0800 Subject: [PATCH 037/144] =?UTF-8?q?=E5=B1=95=E5=BC=80=E6=A0=8F=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=B8=A2=E5=8C=85=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/js/serverstatus.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index 9b34d962..97f0879a 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -83,6 +83,7 @@ function uptime() { "
加载中
" + "
加载中
" + "
加载中
" + + "
加载中
" + "
加载中
" + "" ); @@ -262,6 +263,8 @@ function uptime() { var PING_10010 = result.servers[i].ping_10010.toFixed(0); var PING_189 = result.servers[i].ping_189.toFixed(0); var PING_10086 = result.servers[i].ping_10086.toFixed(0); + ExpandRow[0].children["expand_lost"].innerHTML = "丢包:联通/电信/移动: " + PING_10010 + "% / " + PING_189 + "% / " + PING_10086 + "%" + if (PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20) TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning"; else From 02bbdb18deaa4201ec14b70f47a7f51dabd0219b Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 14:01:42 +0800 Subject: [PATCH 038/144] update lost style --- web/js/serverstatus.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index 97f0879a..a29348cc 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -266,7 +266,9 @@ function uptime() { ExpandRow[0].children["expand_lost"].innerHTML = "丢包:联通/电信/移动: " + PING_10010 + "% / " + PING_189 + "% / " + PING_10086 + "%" if (PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20) - TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning"; + TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger"; + else if (PING_10010 >= 10 || PING_189 >= 10 || PING_10086 >= 10) + TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning"; else TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["ping"].children[0].children[0].innerHTML = PING_10010 + "%💻" + PING_189 + "%💻" + PING_10086 + "%"; From 7f78af03f0b23d3855fa95ffd27acc15443c2bea Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 14:15:37 +0800 Subject: [PATCH 039/144] 100 ping lost --- web/css/dark.css | 4 ++-- web/css/light.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/css/dark.css b/web/css/dark.css index 255e24c9..bb3c7095 100644 --- a/web/css/dark.css +++ b/web/css/dark.css @@ -18,9 +18,9 @@ tr.even.expandRow > :hover { background: #212e36 !important; } tr.odd.expandRow > :hover { background: #212e36 !important; } .expandRow > td { padding: 0 !important; border-top: 0px !important; } #month_traffic { min-width: 85px; max-width: 95px;} -#network { min-width: 115px; } +#network { min-width: 110px; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } -#ping { max-width: 95px; } +#ping { max-width: 100px; } @media only screen and (max-width: 1200px) { #type, tr td:nth-child(4) { display:none; visibility:hidden; } diff --git a/web/css/light.css b/web/css/light.css index 11a78a27..a44e4f19 100644 --- a/web/css/light.css +++ b/web/css/light.css @@ -15,9 +15,9 @@ tr.even.expandRow > :hover { background: #F9F9F9 !important; } tr.odd.expandRow > :hover { background: #FFF !important; } .expandRow > td { padding: 0 !important; border-top: 0px !important; } #month_traffic { min-width: 85px; max-width: 95px;} -#network { min-width: 115px; } +#network { min-width: 110px; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } -#ping { max-width: 95px; } +#ping { max-width: 100px; } @media only screen and (max-width: 1200px) { #type, tr td:nth-child(4) { display:none; visibility:hidden; } From 1004c9a6bd5b25080f63a1b92f53ca702b85c2f4 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 14:25:36 +0800 Subject: [PATCH 040/144] update --- web/js/serverstatus.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index a29348cc..ce3a6923 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -79,7 +79,6 @@ function uptime() { "" + "
" + "
加载中
" + - "
加载中
" + "
加载中
" + "
加载中
" + "
加载中
" + @@ -224,9 +223,8 @@ function uptime() { TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["memory"].children[0].children[0].style.width = Mem + "%"; TableRow.children["memory"].children[0].children[0].innerHTML = Mem + "%"; - ExpandRow[0].children["expand_mem"].innerHTML = "内存: " + bytesToSize(result.servers[i].memory_used*1024, 2) + " / " + bytesToSize(result.servers[i].memory_total*1024, 2); - // Swap - ExpandRow[0].children["expand_swap"].innerHTML = "交换分区: " + bytesToSize(result.servers[i].swap_used*1024, 2) + " / " + bytesToSize(result.servers[i].swap_total*1024, 2); + // 内存|swap + ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 1) + " / " + bytesToSize(result.servers[i].memory_total*1024, 1) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0); // HDD var HDD = ((result.servers[i].hdd_used/result.servers[i].hdd_total)*100.0).toFixed(0); From af8244f1d768bd1ac12e023c66b732f011cab3a7 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 14:53:12 +0800 Subject: [PATCH 041/144] int memory expand --- web/js/serverstatus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index ce3a6923..46b6e4da 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -224,7 +224,7 @@ function uptime() { TableRow.children["memory"].children[0].children[0].style.width = Mem + "%"; TableRow.children["memory"].children[0].children[0].innerHTML = Mem + "%"; // 内存|swap - ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 1) + " / " + bytesToSize(result.servers[i].memory_total*1024, 1) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0); + ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 0) + " / " + bytesToSize(result.servers[i].memory_total*1024, 0) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0); // HDD var HDD = ((result.servers[i].hdd_used/result.servers[i].hdd_total)*100.0).toFixed(0); From 14db7ec943e2b99b06f0e5955e338a7013c522ef Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 16:48:54 +0800 Subject: [PATCH 042/144] update config template --- server/config.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/config.json b/server/config.json index cd64b149..2dd7e9a7 100644 --- a/server/config.json +++ b/server/config.json @@ -22,7 +22,7 @@ "disabled": true, "username": "s03", "name": "node3", - "type": "Nothing", + "type": "hyper", "host": "host3", "location": "🇫🇷", "password": "USER_DEFAULT_PASSWORD", @@ -41,26 +41,26 @@ "watchdog": [ { "name": "cpu high warning", - "rule": "cpu>98", + "rule": "cpu>90&load_1>3", "interval": 600, "callback": "https://yourSMSurl" }, { "name": "memory high warning", "rule": "(memory_used/memory_total)*100>90", - "interval": 600, + "interval": 300, "callback": "https://yourSMSurl" }, { "name": "offline warning", "rule": "online4=0&online6=0", - "interval": 300, + "interval": 600, "callback": "https://yourSMSurl" }, { "name": "you can parse an expression combining any known field", - "rule": "load_5>10", - "interval": 1800, + "rule": "load_5>3", + "interval": 900, "callback": "https://yourSMSurl" } ] From c116067c39151f1537c9eeedfbe0369fc03381c5 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 31 Oct 2022 18:36:33 +0800 Subject: [PATCH 043/144] get to post --- README.md | 2 +- server/src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6136c36d..d6ffef00 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ cd ServerStatus/server && make ```diff ! watchdog rule 可以为任何已知字段的表达式。 ! watchdog interval 最小通知间隔。 -! watchdog callback 可自定义为Get方法的URL,告警内容将拼接其后并发起回调。 +! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调。 ! watchdog callback Telegram:https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text= ! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp= diff --git a/server/src/main.cpp b/server/src/main.cpp index 46d4ac16..36c55919 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -314,7 +314,6 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl time_t currentStamp = (long long)time(/*ago*/0); if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) { - //todo 这里需要换成线程 Client(ClientID)->m_AlarmLastTime = currentStamp; CURL *curl; CURLcode res; @@ -344,6 +343,7 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl sprintf(urlBuffer, "%s%s",Watchdog(ID)->m_aCallback, encodeUrl); + curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); From 333bc29c88aba16233fa6581fa1b04d0f8e98e4a Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 1 Nov 2022 13:38:14 +0800 Subject: [PATCH 044/144] rename old tg to plugin --- .../docker-compose-telegram.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename docker-compose-telegram.yml => plugin/docker-compose-telegram.yml (84%) diff --git a/docker-compose-telegram.yml b/plugin/docker-compose-telegram.yml similarity index 84% rename from docker-compose-telegram.yml rename to plugin/docker-compose-telegram.yml index d5ba31bd..adbe5a72 100644 --- a/docker-compose-telegram.yml +++ b/plugin/docker-compose-telegram.yml @@ -2,7 +2,7 @@ version: "3" services: serverstatus: build: - context: . + context: .. dockerfile: Dockerfile image: serverstatus_server container_name: serverstatus @@ -11,14 +11,14 @@ services: serverstatus-network: ipv4_address: 172.23.0.2 volumes: - - ./server/config.json:/ServerStatus/server/config.json - - ./web/json:/usr/share/nginx/html/json + - ../server/config.json:/ServerStatus/server/config.json + - ../web/json:/usr/share/nginx/html/json ports: - 35601:35601 - 8080:80 bot: build: - context: ./plugin + context: . dockerfile: Dockerfile-telegram image: serverstatus_bot container_name: bot4sss From 25917f0883a55b60cccb62f713669f829ffa3e41 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 1 Nov 2022 13:47:36 +0800 Subject: [PATCH 045/144] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6ffef00..52bfd3cd 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ wget --no-check-certificate -qO ~/serverstatus-config.json https://raw.githubusercontent.com/cppla/ServerStatus/master/server/config.json && mkdir ~/serverstatus-monthtraffic docker run -d --restart=always --name=serverstatus -v ~/serverstatus-config.json:/ServerStatus/server/config.json -v ~/serverstatus-monthtraffic:/usr/share/nginx/html/json -p 80:80 -p 35601:35601 cppla/serverstatus:latest -`Docker-compose`: docker-compose up -d +`Docker-compose(推荐)`: docker-compose up -d ``` 【客户端】: From 34b1bca5b18cf8ea3da22dae4ca4bdec4644e254 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 3 Nov 2022 14:49:47 +0800 Subject: [PATCH 046/144] =?UTF-8?q?The=20io=5Fcounters=20is=20not=20availa?= =?UTF-8?q?ble=20on=20OS=20X,=20=E5=85=BC=E5=AE=B9=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/client-psutil.py | 74 +++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 3dafb611..97e15b52 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -206,43 +206,47 @@ def _disk_io(): 如果这里做连续性IO,那么普通机械硬盘写入到100Mb/s,那么也能造成硬盘长时间的等待。 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o """ - while True: - # first get a list of all processes and disk io counters - procs = [p for p in psutil.process_iter()] - for p in procs[:]: - try: - p._before = p.io_counters() - except psutil.Error: - procs.remove(p) - continue - disks_before = psutil.disk_io_counters() - - # sleep some time, only when INTERVAL==1 , io read/write per_sec. - # when INTERVAL > 1, io read/write per_INTERVAL - time.sleep(INTERVAL) - - # then retrieve the same info again - for p in procs[:]: - with p.oneshot(): + if "darwin" in sys.platform: + diskIO["read"] = 0 + diskIO["write"] = 0 + else: + while True: + # first get a list of all processes and disk io counters + procs = [p for p in psutil.process_iter()] + for p in procs[:]: try: - p._after = p.io_counters() - p._cmdline = ' '.join(p.cmdline()) - if not p._cmdline: - p._cmdline = p.name() - p._username = p.username() - except (psutil.NoSuchProcess, psutil.ZombieProcess): + p._before = p.io_counters() + except psutil.Error: procs.remove(p) - disks_after = psutil.disk_io_counters() - - # finally calculate results by comparing data before and - # after the interval - for p in procs: - p._read_per_sec = p._after.read_bytes - p._before.read_bytes - p._write_per_sec = p._after.write_bytes - p._before.write_bytes - p._total = p._read_per_sec + p._write_per_sec - - diskIO["read"] = disks_after.read_bytes - disks_before.read_bytes - diskIO["write"] = disks_after.write_bytes - disks_before.write_bytes + continue + disks_before = psutil.disk_io_counters() + + # sleep some time, only when INTERVAL==1 , io read/write per_sec. + # when INTERVAL > 1, io read/write per_INTERVAL + time.sleep(INTERVAL) + + # then retrieve the same info again + for p in procs[:]: + with p.oneshot(): + try: + p._after = p.io_counters() + p._cmdline = ' '.join(p.cmdline()) + if not p._cmdline: + p._cmdline = p.name() + p._username = p.username() + except (psutil.NoSuchProcess, psutil.ZombieProcess): + procs.remove(p) + disks_after = psutil.disk_io_counters() + + # finally calculate results by comparing data before and + # after the interval + for p in procs: + p._read_per_sec = p._after.read_bytes - p._before.read_bytes + p._write_per_sec = p._after.write_bytes - p._before.write_bytes + p._total = p._read_per_sec + p._write_per_sec + + diskIO["read"] = disks_after.read_bytes - disks_before.read_bytes + diskIO["write"] = disks_after.write_bytes - disks_before.write_bytes def get_realtime_data(): ''' From 9f60b7962b46abad0c0f735ff06cb7ecf50bae3e Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 3 Nov 2022 16:25:23 +0800 Subject: [PATCH 047/144] beta macos disk info --- clients/client-psutil.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 97e15b52..0df0d510 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -46,18 +46,23 @@ def get_swap(): return int(Mem.total/1024.0), int(Mem.used/1024.0) def get_hdd(): - valid_fs = [ "ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs" ] - disks = dict() - size = 0 - used = 0 - for disk in psutil.disk_partitions(): - if not disk.device in disks and disk.fstype.lower() in valid_fs: - disks[disk.device] = disk.mountpoint - for disk in disks.values(): - usage = psutil.disk_usage(disk) - size += usage.total - used += usage.used - return int(size/1024.0/1024.0), int(used/1024.0/1024.0) + # todo, 兼容macos ,beta + if "darwin" in sys.platform: + return int(psutil.disk_usage("/").total/1024.0/1024.0), int(psutil.disk_usage("/").used/1024.0/1024.0) + else: + valid_fs = ["ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32", + "exfat", "xfs"] + disks = dict() + size = 0 + used = 0 + for disk in psutil.disk_partitions(): + if not disk.device in disks and disk.fstype.lower() in valid_fs: + disks[disk.device] = disk.mountpoint + for disk in disks.values(): + usage = psutil.disk_usage(disk) + size += usage.total + used += usage.used + return int(size/1024.0/1024.0), int(used/1024.0/1024.0) def get_cpu(): return psutil.cpu_percent(interval=INTERVAL) From a695ef8b3ace5e08989c03d8a1cbee619e9bec9a Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 3 Nov 2022 16:33:16 +0800 Subject: [PATCH 048/144] update for macos --- clients/client-psutil.py | 1 + 1 file changed, 1 insertion(+) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 0df0d510..e1e0818a 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -210,6 +210,7 @@ def _disk_io(): 比如我这里是机械硬盘,大量做随机小文件读写,那么很低的读写也就能造成硬盘长时间的等待。 如果这里做连续性IO,那么普通机械硬盘写入到100Mb/s,那么也能造成硬盘长时间的等待。 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o + macos,暂不处理。 """ if "darwin" in sys.platform: diskIO["read"] = 0 From d602791b11555cfe5e01bcbafc79c58ffe712340 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 3 Nov 2022 16:38:22 +0800 Subject: [PATCH 049/144] macos disk info --- clients/client-psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index e1e0818a..798b4443 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -48,7 +48,7 @@ def get_swap(): def get_hdd(): # todo, 兼容macos ,beta if "darwin" in sys.platform: - return int(psutil.disk_usage("/").total/1024.0/1024.0), int(psutil.disk_usage("/").used/1024.0/1024.0) + return int(psutil.disk_usage("/").total/1024.0/1024.0), int((psutil.disk_usage("/").total-psutil.disk_usage("/").free)/1024.0/1024.0) else: valid_fs = ["ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs"] From 1c606cc79ef4ffafcb6dbf726d399b4094e93245 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 8 Nov 2022 12:52:16 +0800 Subject: [PATCH 050/144] update --- web/js/serverstatus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index 46b6e4da..ce3a6923 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -224,7 +224,7 @@ function uptime() { TableRow.children["memory"].children[0].children[0].style.width = Mem + "%"; TableRow.children["memory"].children[0].children[0].innerHTML = Mem + "%"; // 内存|swap - ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 0) + " / " + bytesToSize(result.servers[i].memory_total*1024, 0) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0); + ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 1) + " / " + bytesToSize(result.servers[i].memory_total*1024, 1) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0); // HDD var HDD = ((result.servers[i].hdd_used/result.servers[i].hdd_total)*100.0).toFixed(0); From b551998eb8eaab2936a3fde6b18eb10eb9647832 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 30 Nov 2022 10:31:04 +0800 Subject: [PATCH 051/144] get macos load --- clients/client-psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 798b4443..ab8a806c 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -354,7 +354,7 @@ def byte_str(object): CPU = get_cpu() NET_IN, NET_OUT = liuliang() Uptime = get_uptime() - Load_1, Load_5, Load_15 = os.getloadavg() if 'linux' in sys.platform else (0.0, 0.0, 0.0) + Load_1, Load_5, Load_15 = os.getloadavg() if 'linux' in sys.platform or 'darwin' in sys.platform else (0.0, 0.0, 0.0) MemoryTotal, MemoryUsed = get_memory() SwapTotal, SwapUsed = get_swap() HDDTotal, HDDUsed = get_hdd() From c77e00476cc454951e9b1ac0dd91af7a90f8ef2e Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 30 Nov 2022 11:02:09 +0800 Subject: [PATCH 052/144] get macos tudp --- clients/client-psutil.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index ab8a806c..f81359d7 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -93,13 +93,24 @@ def tupd(): u = int(os.popen('ss -u|wc -l').read()[:-1])-1 p = int(os.popen('ps -ef|wc -l').read()[:-1])-2 d = int(os.popen('ps -eLf|wc -l').read()[:-1])-2 + elif sys.platform.startswith("darwin") is True: + t = int(os.popen('lsof -nP -iTCP | wc -l').read()[:-1]) - 1 + u = int(os.popen('lsof -nP -iUDP | wc -l').read()[:-1]) - 1 + p = len(psutil.pids()) + d = 0 + for k in psutil.pids(): + try: + d += psutil.Process(k).num_threads() + except: + pass + elif sys.platform.startswith("win") is True: t = int(os.popen('netstat -an|find "TCP" /c').read()[:-1])-1 u = int(os.popen('netstat -an|find "UDP" /c').read()[:-1])-1 p = len(psutil.pids()) d = 0 # cpu is high, default: 0 - # d = sum([psutil.Process(k).num_threads() for k in [x for x in psutil.pids()]]) + # d = sum([psutil.Process(k).num_threads() for k in psutil.pids()]) else: t,u,p,d = 0,0,0,0 return t,u,p,d From d5af5445dfb18dbb004997e6d96eab29d4dd79e7 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 30 Nov 2022 11:09:21 +0800 Subject: [PATCH 053/144] disk io not in win --- clients/client-psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index f81359d7..bc16a8ce 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -223,7 +223,7 @@ def _disk_io(): 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o macos,暂不处理。 """ - if "darwin" in sys.platform: + if "darwin" in sys.platform or "win" in sys.platform: diskIO["read"] = 0 diskIO["write"] = 0 else: From 806b60bd6ba1e838da59e01eccaeb01bc3f11c2c Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 30 Nov 2022 11:17:12 +0800 Subject: [PATCH 054/144] get macos infomation build --- clients/client-psutil.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index bc16a8ce..19403cd3 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -46,7 +46,6 @@ def get_swap(): return int(Mem.total/1024.0), int(Mem.used/1024.0) def get_hdd(): - # todo, 兼容macos ,beta if "darwin" in sys.platform: return int(psutil.disk_usage("/").total/1024.0/1024.0), int((psutil.disk_usage("/").total-psutil.disk_usage("/").free)/1024.0/1024.0) else: @@ -108,9 +107,8 @@ def tupd(): t = int(os.popen('netstat -an|find "TCP" /c').read()[:-1])-1 u = int(os.popen('netstat -an|find "UDP" /c').read()[:-1])-1 p = len(psutil.pids()) - d = 0 - # cpu is high, default: 0 - # d = sum([psutil.Process(k).num_threads() for k in psutil.pids()]) + # if you find cpu is high, please set d=0 + d = sum([psutil.Process(k).num_threads() for k in psutil.pids()]) else: t,u,p,d = 0,0,0,0 return t,u,p,d @@ -221,7 +219,7 @@ def _disk_io(): 比如我这里是机械硬盘,大量做随机小文件读写,那么很低的读写也就能造成硬盘长时间的等待。 如果这里做连续性IO,那么普通机械硬盘写入到100Mb/s,那么也能造成硬盘长时间的等待。 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o - macos,暂不处理。 + macos/win,暂不处理。 """ if "darwin" in sys.platform or "win" in sys.platform: diskIO["read"] = 0 From 52d62afa59a6c8928a610f8b65f08b304b7b8892 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 28 Feb 2023 17:19:49 +0800 Subject: [PATCH 055/144] =?UTF-8?q?=E4=BC=98=E5=8C=96curl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 36c55919..9d2343f9 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -343,8 +343,11 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl sprintf(urlBuffer, "%s%s",Watchdog(ID)->m_aCallback, encodeUrl); - curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"signature=ServerStatus"); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); res = curl_easy_perform(curl); From 979a9b5d871aabd9da2ac99a460f6fc53cc67fea Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 13 Mar 2023 07:23:44 +0000 Subject: [PATCH 056/144] =?UTF-8?q?=E5=8A=A0=E4=B8=80=E4=B8=AAddcc?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 ++++++++++++++++++ server/config.json | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 52bfd3cd..992ad850 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,24 @@ cd ServerStatus/server && make "interval": 600, "callback": "https://yourSMSurl" }, + { + "name": "服务器内存使用率过高监控", + "rule": "(memory_used/memory_total)*100>90", + "interval": 600, + "callback": "https://yourSMSurl" + }, + { + "name": "服务器宕机告警", + "rule": "online4=0&online6=0", + "interval": 600, + "callback": "https://yourSMSurl" + }, + { + "name": "DDOS和CC攻击监控", + "rule": "tcp_count>1000", + "interval": 300, + "callback": "https://yourSMSurl" + }, { "name": "你可以组合任何已知字段的表达式", "rule": "(hdd_used/hdd_total)*100>95", diff --git a/server/config.json b/server/config.json index 2dd7e9a7..e07ad529 100644 --- a/server/config.json +++ b/server/config.json @@ -57,6 +57,12 @@ "interval": 600, "callback": "https://yourSMSurl" }, + { + "name": "ddcc attack", + "rule": "tcp_count>1000", + "interval": 300, + "callback": "https://yourSMSurl" + }, { "name": "you can parse an expression combining any known field", "rule": "load_5>3", From 4b1ec57c6da854f9c59ed1f2dbaf4b2216ce7441 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 3 Apr 2023 15:12:33 +0800 Subject: [PATCH 057/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=9C=88=E5=87=BA=E5=8F=A3=E6=B5=81=E9=87=8F=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ server/config.json | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 992ad850..eb42b567 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ cd ServerStatus/server && make "interval": 300, "callback": "https://yourSMSurl" }, + { + "name": "服务器月出口流量999GB告警", + "rule": "(network_out-last_network_out)/1024/1024/1024>999", + "interval": 3600, + "callback": "https://yourSMSurl" + }, { "name": "你可以组合任何已知字段的表达式", "rule": "(hdd_used/hdd_total)*100>95", diff --git a/server/config.json b/server/config.json index e07ad529..21628e23 100644 --- a/server/config.json +++ b/server/config.json @@ -63,6 +63,12 @@ "interval": 300, "callback": "https://yourSMSurl" }, + { + "name": "month traffic warning", + "rule": "(network_out-last_network_out)/1024/1024/1024>999", + "interval": 3600, + "callback": "https://yourSMSurl" + }, { "name": "you can parse an expression combining any known field", "rule": "load_5>3", From 8ad927d88d953b9a1a969803caa34371d34923e4 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 3 Apr 2023 15:22:59 +0800 Subject: [PATCH 058/144] jquery v3.3.1 to v3.5.0 --- web/js/jquery.min.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/js/jquery.min.js b/web/js/jquery.min.js index 4d9b3a25..47b63970 100644 --- a/web/js/jquery.min.js +++ b/web/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + + + +
+

+ Light Default +

+
+
+ Powered by ServerStatus-Rust. + Theme Light by OriLight +
+
+ + + + From 59fa2d8eabafaac5c311a3a7ff753fabd3e11aaa Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 17 Oct 2023 01:46:19 +0000 Subject: [PATCH 086/144] fix light bug --- web/assets/index-982ea826.js | 1 - web/assets/index-e069a4f0.js | 1 + web/index3.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 web/assets/index-982ea826.js create mode 100644 web/assets/index-e069a4f0.js diff --git a/web/assets/index-982ea826.js b/web/assets/index-982ea826.js deleted file mode 100644 index 2cfe3cb4..00000000 --- a/web/assets/index-982ea826.js +++ /dev/null @@ -1 +0,0 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))r(n);new MutationObserver(n=>{for(const o of n)if(o.type==="childList")for(const l of o.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function s(n){const o={};return n.integrity&&(o.integrity=n.integrity),n.referrerPolicy&&(o.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?o.credentials="include":n.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(n){if(n.ep)return;n.ep=!0;const o=s(n);fetch(n.href,o)}})();function Is(e,t){const s=Object.create(null),r=e.split(",");for(let n=0;n!!s[n.toLowerCase()]:n=>!!s[n]}const K={},Qe=[],be=()=>{},Fr=()=>!1,Ar=/^on[^a-z]/,zt=e=>Ar.test(e),Ms=e=>e.startsWith("onUpdate:"),G=Object.assign,Fs=(e,t)=>{const s=e.indexOf(t);s>-1&&e.splice(s,1)},$r=Object.prototype.hasOwnProperty,S=(e,t)=>$r.call(e,t),P=Array.isArray,Ge=e=>qt(e)==="[object Map]",$n=e=>qt(e)==="[object Set]",M=e=>typeof e=="function",V=e=>typeof e=="string",As=e=>typeof e=="symbol",W=e=>e!==null&&typeof e=="object",Rn=e=>W(e)&&M(e.then)&&M(e.catch),Sn=Object.prototype.toString,qt=e=>Sn.call(e),Rr=e=>qt(e).slice(8,-1),jn=e=>qt(e)==="[object Object]",$s=e=>V(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Bt=Is(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Yt=e=>{const t=Object.create(null);return s=>t[s]||(t[s]=e(s))},Sr=/-(\w)/g,st=Yt(e=>e.replace(Sr,(t,s)=>s?s.toUpperCase():"")),jr=/\B([A-Z])/g,lt=Yt(e=>e.replace(jr,"-$1").toLowerCase()),Nn=Yt(e=>e.charAt(0).toUpperCase()+e.slice(1)),ls=Yt(e=>e?`on${Nn(e)}`:""),bt=(e,t)=>!Object.is(e,t),is=(e,t)=>{for(let s=0;s{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:s})},Nr=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let tn;const gs=()=>tn||(tn=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Jt(e){if(P(e)){const t={};for(let s=0;s{if(s){const r=s.split(Dr);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function it(e){let t="";if(V(e))t=e;else if(P(e))for(let s=0;sV(e)?e:e==null?"":P(e)||W(e)&&(e.toString===Sn||!M(e.toString))?JSON.stringify(e,Dn,2):String(e),Dn=(e,t)=>t&&t.__v_isRef?Dn(e,t.value):Ge(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((s,[r,n])=>(s[`${r} =>`]=n,s),{})}:$n(t)?{[`Set(${t.size})`]:[...t.values()]}:W(t)&&!P(t)&&!jn(t)?String(t):t;let _e;class kr{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=_e,!t&&_e&&(this.index=(_e.scopes||(_e.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const s=_e;try{return _e=this,t()}finally{_e=s}}}on(){_e=this}off(){_e=this.parent}stop(t){if(this._active){let s,r;for(s=0,r=this.effects.length;s{const t=new Set(e);return t.w=0,t.n=0,t},Hn=e=>(e.w&Ne)>0,Ln=e=>(e.n&Ne)>0,qr=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let s=0;for(let r=0;r{(g==="length"||g>=u)&&c.push(a)})}else switch(s!==void 0&&c.push(l.get(s)),t){case"add":P(e)?$s(s)&&c.push(l.get("length")):(c.push(l.get(qe)),Ge(e)&&c.push(l.get(vs)));break;case"delete":P(e)||(c.push(l.get(qe)),Ge(e)&&c.push(l.get(vs)));break;case"set":Ge(e)&&c.push(l.get(qe));break}if(c.length===1)c[0]&&bs(c[0]);else{const u=[];for(const a of c)a&&u.push(...a);bs(Rs(u))}}function bs(e,t){const s=P(e)?e:[...e];for(const r of s)r.computed&&nn(r);for(const r of s)r.computed||nn(r)}function nn(e,t){(e!==me||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}const Jr=Is("__proto__,__v_isRef,__isVue"),kn=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(As)),Zr=js(),Vr=js(!1,!0),Xr=js(!0),rn=Qr();function Qr(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...s){const r=N(this);for(let o=0,l=this.length;o{e[t]=function(...s){ct();const r=N(this)[t].apply(this,s);return ft(),r}}),e}function Gr(e){const t=N(this);return ae(t,"has",e),t.hasOwnProperty(e)}function js(e=!1,t=!1){return function(r,n,o){if(n==="__v_isReactive")return!e;if(n==="__v_isReadonly")return e;if(n==="__v_isShallow")return t;if(n==="__v_raw"&&o===(e?t?_o:Jn:t?Yn:qn).get(r))return r;const l=P(r);if(!e){if(l&&S(rn,n))return Reflect.get(rn,n,o);if(n==="hasOwnProperty")return Gr}const c=Reflect.get(r,n,o);return(As(n)?kn.has(n):Jr(n))||(e||ae(r,"get",n),t)?c:le(c)?l&&$s(n)?c:c.value:W(c)?e?Zn(c):Ds(c):c}}const eo=Wn(),to=Wn(!0);function Wn(e=!1){return function(s,r,n,o){let l=s[r];if(nt(l)&&le(l)&&!le(n))return!1;if(!e&&(!Ut(n)&&!nt(n)&&(l=N(l),n=N(n)),!P(s)&&le(l)&&!le(n)))return l.value=n,!0;const c=P(s)&&$s(r)?Number(r)e,Zt=e=>Reflect.getPrototypeOf(e);function Ft(e,t,s=!1,r=!1){e=e.__v_raw;const n=N(e),o=N(t);s||(t!==o&&ae(n,"get",t),ae(n,"get",o));const{has:l}=Zt(n),c=r?Ns:s?Ls:yt;if(l.call(n,t))return c(e.get(t));if(l.call(n,o))return c(e.get(o));e!==n&&e.get(t)}function At(e,t=!1){const s=this.__v_raw,r=N(s),n=N(e);return t||(e!==n&&ae(r,"has",e),ae(r,"has",n)),e===n?s.has(e):s.has(e)||s.has(n)}function $t(e,t=!1){return e=e.__v_raw,!t&&ae(N(e),"iterate",qe),Reflect.get(e,"size",e)}function on(e){e=N(e);const t=N(this);return Zt(t).has.call(t,e)||(t.add(e),Me(t,"add",e,e)),this}function ln(e,t){t=N(t);const s=N(this),{has:r,get:n}=Zt(s);let o=r.call(s,e);o||(e=N(e),o=r.call(s,e));const l=n.call(s,e);return s.set(e,t),o?bt(t,l)&&Me(s,"set",e,t):Me(s,"add",e,t),this}function cn(e){const t=N(this),{has:s,get:r}=Zt(t);let n=s.call(t,e);n||(e=N(e),n=s.call(t,e)),r&&r.call(t,e);const o=t.delete(e);return n&&Me(t,"delete",e,void 0),o}function fn(){const e=N(this),t=e.size!==0,s=e.clear();return t&&Me(e,"clear",void 0,void 0),s}function Rt(e,t){return function(r,n){const o=this,l=o.__v_raw,c=N(l),u=t?Ns:e?Ls:yt;return!e&&ae(c,"iterate",qe),l.forEach((a,g)=>r.call(n,u(a),u(g),o))}}function St(e,t,s){return function(...r){const n=this.__v_raw,o=N(n),l=Ge(o),c=e==="entries"||e===Symbol.iterator&&l,u=e==="keys"&&l,a=n[e](...r),g=s?Ns:t?Ls:yt;return!t&&ae(o,"iterate",u?vs:qe),{next(){const{value:x,done:E}=a.next();return E?{value:x,done:E}:{value:c?[g(x[0]),g(x[1])]:g(x),done:E}},[Symbol.iterator](){return this}}}}function $e(e){return function(...t){return e==="delete"?!1:this}}function io(){const e={get(o){return Ft(this,o)},get size(){return $t(this)},has:At,add:on,set:ln,delete:cn,clear:fn,forEach:Rt(!1,!1)},t={get(o){return Ft(this,o,!1,!0)},get size(){return $t(this)},has:At,add:on,set:ln,delete:cn,clear:fn,forEach:Rt(!1,!0)},s={get(o){return Ft(this,o,!0)},get size(){return $t(this,!0)},has(o){return At.call(this,o,!0)},add:$e("add"),set:$e("set"),delete:$e("delete"),clear:$e("clear"),forEach:Rt(!0,!1)},r={get(o){return Ft(this,o,!0,!0)},get size(){return $t(this,!0)},has(o){return At.call(this,o,!0)},add:$e("add"),set:$e("set"),delete:$e("delete"),clear:$e("clear"),forEach:Rt(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(o=>{e[o]=St(o,!1,!1),s[o]=St(o,!0,!1),t[o]=St(o,!1,!0),r[o]=St(o,!0,!0)}),[e,s,t,r]}const[co,fo,uo,ao]=io();function Bs(e,t){const s=t?e?ao:uo:e?fo:co;return(r,n,o)=>n==="__v_isReactive"?!e:n==="__v_isReadonly"?e:n==="__v_raw"?r:Reflect.get(S(s,n)&&n in r?s:r,n,o)}const ho={get:Bs(!1,!1)},po={get:Bs(!1,!0)},go={get:Bs(!0,!1)},qn=new WeakMap,Yn=new WeakMap,Jn=new WeakMap,_o=new WeakMap;function mo(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function vo(e){return e.__v_skip||!Object.isExtensible(e)?0:mo(Rr(e))}function Ds(e){return nt(e)?e:Hs(e,!1,zn,ho,qn)}function bo(e){return Hs(e,!1,lo,po,Yn)}function Zn(e){return Hs(e,!0,oo,go,Jn)}function Hs(e,t,s,r,n){if(!W(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const o=n.get(e);if(o)return o;const l=vo(e);if(l===0)return e;const c=new Proxy(e,l===2?r:s);return n.set(e,c),c}function et(e){return nt(e)?et(e.__v_raw):!!(e&&e.__v_isReactive)}function nt(e){return!!(e&&e.__v_isReadonly)}function Ut(e){return!!(e&&e.__v_isShallow)}function Vn(e){return et(e)||nt(e)}function N(e){const t=e&&e.__v_raw;return t?N(t):e}function Xn(e){return Lt(e,"__v_skip",!0),e}const yt=e=>W(e)?Ds(e):e,Ls=e=>W(e)?Zn(e):e;function Qn(e){Se&&me&&(e=N(e),Kn(e.dep||(e.dep=Rs())))}function Gn(e,t){e=N(e);const s=e.dep;s&&bs(s)}function le(e){return!!(e&&e.__v_isRef===!0)}function jt(e){return yo(e,!1)}function yo(e,t){return le(e)?e:new xo(e,t)}class xo{constructor(t,s){this.__v_isShallow=s,this.dep=void 0,this.__v_isRef=!0,this._rawValue=s?t:N(t),this._value=s?t:yt(t)}get value(){return Qn(this),this._value}set value(t){const s=this.__v_isShallow||Ut(t)||nt(t);t=s?t:N(t),bt(t,this._rawValue)&&(this._rawValue=t,this._value=s?t:yt(t),Gn(this))}}function U(e){return le(e)?e.value:e}const wo={get:(e,t,s)=>U(Reflect.get(e,t,s)),set:(e,t,s,r)=>{const n=e[t];return le(n)&&!le(s)?(n.value=s,!0):Reflect.set(e,t,s,r)}};function er(e){return et(e)?e:new Proxy(e,wo)}class Eo{constructor(t,s,r,n){this._setter=s,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Ss(t,()=>{this._dirty||(this._dirty=!0,Gn(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!n,this.__v_isReadonly=r}get value(){const t=N(this);return Qn(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function Co(e,t,s=!1){let r,n;const o=M(e);return o?(r=e,n=be):(r=e.get,n=e.set),new Eo(r,n,o||!n,s)}function je(e,t,s,r){let n;try{n=r?e(...r):e()}catch(o){Vt(o,t,s)}return n}function ye(e,t,s,r){if(M(e)){const o=je(e,t,s,r);return o&&Rn(o)&&o.catch(l=>{Vt(l,t,s)}),o}const n=[];for(let o=0;o>>1;wt(re[r])Te&&re.splice(t,1)}function Mo(e){P(e)?tt.push(...e):(!Ie||!Ie.includes(e,e.allowRecurse?We+1:We))&&tt.push(e),sr()}function un(e,t=xt?Te+1:0){for(;twt(s)-wt(r)),We=0;Wee.id==null?1/0:e.id,Fo=(e,t)=>{const s=wt(e)-wt(t);if(s===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return s};function rr(e){ys=!1,xt=!0,re.sort(Fo);const t=be;try{for(Te=0;TeV(I)?I.trim():I)),x&&(n=s.map(Nr))}let c,u=r[c=ls(t)]||r[c=ls(st(t))];!u&&o&&(u=r[c=ls(lt(t))]),u&&ye(u,e,6,n);const a=r[c+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[c])return;e.emitted[c]=!0,ye(a,e,6,n)}}function or(e,t,s=!1){const r=t.emitsCache,n=r.get(e);if(n!==void 0)return n;const o=e.emits;let l={},c=!1;if(!M(e)){const u=a=>{const g=or(a,t,!0);g&&(c=!0,G(l,g))};!s&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}return!o&&!c?(W(e)&&r.set(e,null),null):(P(o)?o.forEach(u=>l[u]=null):G(l,o),W(e)&&r.set(e,l),l)}function Xt(e,t){return!e||!zt(t)?!1:(t=t.slice(2).replace(/Once$/,""),S(e,t[0].toLowerCase()+t.slice(1))||S(e,lt(t))||S(e,t))}let ue=null,lr=null;function Kt(e){const t=ue;return ue=e,lr=e&&e.type.__scopeId||null,t}function Q(e,t=ue,s){if(!t||e._n)return e;const r=(...n)=>{r._d&&yn(-1);const o=Kt(t);let l;try{l=e(...n)}finally{Kt(o),r._d&&yn(1)}return l};return r._n=!0,r._c=!0,r._d=!0,r}function cs(e){const{type:t,vnode:s,proxy:r,withProxy:n,props:o,propsOptions:[l],slots:c,attrs:u,emit:a,render:g,renderCache:x,data:E,setupState:I,ctx:Y,inheritAttrs:$}=e;let X,te;const se=Kt(e);try{if(s.shapeFlag&4){const F=n||r;X=Oe(g.call(F,F,x,o,I,E,Y)),te=u}else{const F=t;X=Oe(F.length>1?F(o,{attrs:u,slots:c,emit:a}):F(o,null)),te=t.props?u:$o(u)}}catch(F){vt.length=0,Vt(F,e,1),X=L(Be)}let ne=X;if(te&&$!==!1){const F=Object.keys(te),{shapeFlag:Ae}=ne;F.length&&Ae&7&&(l&&F.some(Ms)&&(te=Ro(te,l)),ne=rt(ne,te))}return s.dirs&&(ne=rt(ne),ne.dirs=ne.dirs?ne.dirs.concat(s.dirs):s.dirs),s.transition&&(ne.transition=s.transition),X=ne,Kt(se),X}const $o=e=>{let t;for(const s in e)(s==="class"||s==="style"||zt(s))&&((t||(t={}))[s]=e[s]);return t},Ro=(e,t)=>{const s={};for(const r in e)(!Ms(r)||!(r.slice(9)in t))&&(s[r]=e[r]);return s};function So(e,t,s){const{props:r,children:n,component:o}=e,{props:l,children:c,patchFlag:u}=t,a=o.emitsOptions;if(t.dirs||t.transition)return!0;if(s&&u>=0){if(u&1024)return!0;if(u&16)return r?an(r,l,a):!!l;if(u&8){const g=t.dynamicProps;for(let x=0;xe.__isSuspense;function Bo(e,t){t&&t.pendingBranch?P(e)?t.effects.push(...e):t.effects.push(e):Mo(e)}const Nt={};function fs(e,t,s){return ir(e,t,s)}function ir(e,t,{immediate:s,deep:r,flush:n,onTrack:o,onTrigger:l}=K){var c;const u=zr()===((c=oe)==null?void 0:c.scope)?oe:null;let a,g=!1,x=!1;if(le(e)?(a=()=>e.value,g=Ut(e)):et(e)?(a=()=>e,r=!0):P(e)?(x=!0,g=e.some(F=>et(F)||Ut(F)),a=()=>e.map(F=>{if(le(F))return F.value;if(et(F))return Xe(F);if(M(F))return je(F,u,2)})):M(e)?t?a=()=>je(e,u,2):a=()=>{if(!(u&&u.isUnmounted))return E&&E(),ye(e,u,3,[I])}:a=be,t&&r){const F=a;a=()=>Xe(F())}let E,I=F=>{E=se.onStop=()=>{je(F,u,4)}},Y;if(Ct)if(I=be,t?s&&ye(t,u,3,[a(),x?[]:void 0,I]):a(),n==="sync"){const F=Ml();Y=F.__watcherHandles||(F.__watcherHandles=[])}else return be;let $=x?new Array(e.length).fill(Nt):Nt;const X=()=>{if(se.active)if(t){const F=se.run();(r||g||(x?F.some((Ae,ut)=>bt(Ae,$[ut])):bt(F,$)))&&(E&&E(),ye(t,u,3,[F,$===Nt?void 0:x&&$[0]===Nt?[]:$,I]),$=F)}else se.run()};X.allowRecurse=!!t;let te;n==="sync"?te=X:n==="post"?te=()=>fe(X,u&&u.suspense):(X.pre=!0,u&&(X.id=u.uid),te=()=>Ks(X));const se=new Ss(a,te);t?s?X():$=se.run():n==="post"?fe(se.run.bind(se),u&&u.suspense):se.run();const ne=()=>{se.stop(),u&&u.scope&&Fs(u.scope.effects,se)};return Y&&Y.push(ne),ne}function Do(e,t,s){const r=this.proxy,n=V(e)?e.includes(".")?cr(r,e):()=>r[e]:e.bind(r,r);let o;M(t)?o=t:(o=t.handler,s=t);const l=oe;ot(this);const c=ir(n,o.bind(r),s);return l?ot(l):Ye(),c}function cr(e,t){const s=t.split(".");return()=>{let r=e;for(let n=0;n{Xe(s,t)});else if(jn(e))for(const s in e)Xe(e[s],t);return e}function Ke(e,t,s,r){const n=e.dirs,o=t&&t.dirs;for(let l=0;lG({name:e.name},t,{setup:e}))():e}const _t=e=>!!e.type.__asyncLoader,fr=e=>e.type.__isKeepAlive;function Ho(e,t){ur(e,"a",t)}function Lo(e,t){ur(e,"da",t)}function ur(e,t,s=oe){const r=e.__wdc||(e.__wdc=()=>{let n=s;for(;n;){if(n.isDeactivated)return;n=n.parent}return e()});if(Gt(t,r,s),s){let n=s.parent;for(;n&&n.parent;)fr(n.parent.vnode)&&Uo(r,t,s,n),n=n.parent}}function Uo(e,t,s,r){const n=Gt(t,e,r,!0);dr(()=>{Fs(r[t],n)},s)}function Gt(e,t,s=oe,r=!1){if(s){const n=s[e]||(s[e]=[]),o=t.__weh||(t.__weh=(...l)=>{if(s.isUnmounted)return;ct(),ot(s);const c=ye(t,s,e,l);return Ye(),ft(),c});return r?n.unshift(o):n.push(o),o}}const Fe=e=>(t,s=oe)=>(!Ct||e==="sp")&&Gt(e,(...r)=>t(...r),s),Ko=Fe("bm"),ar=Fe("m"),ko=Fe("bu"),Wo=Fe("u"),zo=Fe("bum"),dr=Fe("um"),qo=Fe("sp"),Yo=Fe("rtg"),Jo=Fe("rtc");function Zo(e,t=oe){Gt("ec",e,t)}const Vo=Symbol.for("v-ndc");function Xo(e,t,s,r){let n;const o=s&&s[r];if(P(e)||V(e)){n=new Array(e.length);for(let l=0,c=e.length;lt(l,c,void 0,o&&o[c]));else{const l=Object.keys(e);n=new Array(l.length);for(let c=0,u=l.length;cCr(t)?!(t.type===Be||t.type===he&&!pr(t.children)):!0)?e:null}const xs=e=>e?Tr(e)?Ys(e)||e.proxy:xs(e.parent):null,mt=G(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>xs(e.parent),$root:e=>xs(e.root),$emit:e=>e.emit,$options:e=>ks(e),$forceUpdate:e=>e.f||(e.f=()=>Ks(e.update)),$nextTick:e=>e.n||(e.n=To.bind(e.proxy)),$watch:e=>Do.bind(e)}),us=(e,t)=>e!==K&&!e.__isScriptSetup&&S(e,t),Qo={get({_:e},t){const{ctx:s,setupState:r,data:n,props:o,accessCache:l,type:c,appContext:u}=e;let a;if(t[0]!=="$"){const I=l[t];if(I!==void 0)switch(I){case 1:return r[t];case 2:return n[t];case 4:return s[t];case 3:return o[t]}else{if(us(r,t))return l[t]=1,r[t];if(n!==K&&S(n,t))return l[t]=2,n[t];if((a=e.propsOptions[0])&&S(a,t))return l[t]=3,o[t];if(s!==K&&S(s,t))return l[t]=4,s[t];ws&&(l[t]=0)}}const g=mt[t];let x,E;if(g)return t==="$attrs"&&ae(e,"get",t),g(e);if((x=c.__cssModules)&&(x=x[t]))return x;if(s!==K&&S(s,t))return l[t]=4,s[t];if(E=u.config.globalProperties,S(E,t))return E[t]},set({_:e},t,s){const{data:r,setupState:n,ctx:o}=e;return us(n,t)?(n[t]=s,!0):r!==K&&S(r,t)?(r[t]=s,!0):S(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(o[t]=s,!0)},has({_:{data:e,setupState:t,accessCache:s,ctx:r,appContext:n,propsOptions:o}},l){let c;return!!s[l]||e!==K&&S(e,l)||us(t,l)||(c=o[0])&&S(c,l)||S(r,l)||S(mt,l)||S(n.config.globalProperties,l)},defineProperty(e,t,s){return s.get!=null?e._.accessCache[t]=0:S(s,"value")&&this.set(e,t,s.value,null),Reflect.defineProperty(e,t,s)}};function dn(e){return P(e)?e.reduce((t,s)=>(t[s]=null,t),{}):e}let ws=!0;function Go(e){const t=ks(e),s=e.proxy,r=e.ctx;ws=!1,t.beforeCreate&&hn(t.beforeCreate,e,"bc");const{data:n,computed:o,methods:l,watch:c,provide:u,inject:a,created:g,beforeMount:x,mounted:E,beforeUpdate:I,updated:Y,activated:$,deactivated:X,beforeDestroy:te,beforeUnmount:se,destroyed:ne,unmounted:F,render:Ae,renderTracked:ut,renderTriggered:Ot,errorCaptured:De,serverPrefetch:ss,expose:He,inheritAttrs:at,components:Tt,directives:Pt,filters:ns}=t;if(a&&el(a,r,null),l)for(const z in l){const D=l[z];M(D)&&(r[z]=D.bind(s))}if(n){const z=n.call(s,s);W(z)&&(e.data=Ds(z))}if(ws=!0,o)for(const z in o){const D=o[z],Le=M(D)?D.bind(s,s):M(D.get)?D.get.bind(s,s):be,It=!M(D)&&M(D.set)?D.set.bind(s):be,Ue=Ts({get:Le,set:It});Object.defineProperty(r,z,{enumerable:!0,configurable:!0,get:()=>Ue.value,set:xe=>Ue.value=xe})}if(c)for(const z in c)gr(c[z],r,s,z);if(u){const z=M(u)?u.call(s):u;Reflect.ownKeys(z).forEach(D=>{ll(D,z[D])})}g&&hn(g,e,"c");function ie(z,D){P(D)?D.forEach(Le=>z(Le.bind(s))):D&&z(D.bind(s))}if(ie(Ko,x),ie(ar,E),ie(ko,I),ie(Wo,Y),ie(Ho,$),ie(Lo,X),ie(Zo,De),ie(Jo,ut),ie(Yo,Ot),ie(zo,se),ie(dr,F),ie(qo,ss),P(He))if(He.length){const z=e.exposed||(e.exposed={});He.forEach(D=>{Object.defineProperty(z,D,{get:()=>s[D],set:Le=>s[D]=Le})})}else e.exposed||(e.exposed={});Ae&&e.render===be&&(e.render=Ae),at!=null&&(e.inheritAttrs=at),Tt&&(e.components=Tt),Pt&&(e.directives=Pt)}function el(e,t,s=be){P(e)&&(e=Es(e));for(const r in e){const n=e[r];let o;W(n)?"default"in n?o=Dt(n.from||r,n.default,!0):o=Dt(n.from||r):o=Dt(n),le(o)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>o.value,set:l=>o.value=l}):t[r]=o}}function hn(e,t,s){ye(P(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,s)}function gr(e,t,s,r){const n=r.includes(".")?cr(s,r):()=>s[r];if(V(e)){const o=t[e];M(o)&&fs(n,o)}else if(M(e))fs(n,e.bind(s));else if(W(e))if(P(e))e.forEach(o=>gr(o,t,s,r));else{const o=M(e.handler)?e.handler.bind(s):t[e.handler];M(o)&&fs(n,o,e)}}function ks(e){const t=e.type,{mixins:s,extends:r}=t,{mixins:n,optionsCache:o,config:{optionMergeStrategies:l}}=e.appContext,c=o.get(t);let u;return c?u=c:!n.length&&!s&&!r?u=t:(u={},n.length&&n.forEach(a=>kt(u,a,l,!0)),kt(u,t,l)),W(t)&&o.set(t,u),u}function kt(e,t,s,r=!1){const{mixins:n,extends:o}=t;o&&kt(e,o,s,!0),n&&n.forEach(l=>kt(e,l,s,!0));for(const l in t)if(!(r&&l==="expose")){const c=tl[l]||s&&s[l];e[l]=c?c(e[l],t[l]):t[l]}return e}const tl={data:pn,props:gn,emits:gn,methods:gt,computed:gt,beforeCreate:ce,created:ce,beforeMount:ce,mounted:ce,beforeUpdate:ce,updated:ce,beforeDestroy:ce,beforeUnmount:ce,destroyed:ce,unmounted:ce,activated:ce,deactivated:ce,errorCaptured:ce,serverPrefetch:ce,components:gt,directives:gt,watch:nl,provide:pn,inject:sl};function pn(e,t){return t?e?function(){return G(M(e)?e.call(this,this):e,M(t)?t.call(this,this):t)}:t:e}function sl(e,t){return gt(Es(e),Es(t))}function Es(e){if(P(e)){const t={};for(let s=0;s1)return s&&M(t)?t.call(r&&r.proxy):t}}function il(e,t,s,r=!1){const n={},o={};Lt(o,ts,1),e.propsDefaults=Object.create(null),mr(e,t,n,o);for(const l in e.propsOptions[0])l in n||(n[l]=void 0);s?e.props=r?n:bo(n):e.type.props?e.props=n:e.props=o,e.attrs=o}function cl(e,t,s,r){const{props:n,attrs:o,vnode:{patchFlag:l}}=e,c=N(n),[u]=e.propsOptions;let a=!1;if((r||l>0)&&!(l&16)){if(l&8){const g=e.vnode.dynamicProps;for(let x=0;x{u=!0;const[E,I]=vr(x,t,!0);G(l,E),I&&c.push(...I)};!s&&t.mixins.length&&t.mixins.forEach(g),e.extends&&g(e.extends),e.mixins&&e.mixins.forEach(g)}if(!o&&!u)return W(e)&&r.set(e,Qe),Qe;if(P(o))for(let g=0;g-1,I[1]=$<0||Y<$,(Y>-1||S(I,"default"))&&c.push(x)}}}const a=[l,c];return W(e)&&r.set(e,a),a}function _n(e){return e[0]!=="$"}function mn(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function vn(e,t){return mn(e)===mn(t)}function bn(e,t){return P(t)?t.findIndex(s=>vn(s,e)):M(t)&&vn(t,e)?0:-1}const br=e=>e[0]==="_"||e==="$stable",Ws=e=>P(e)?e.map(Oe):[Oe(e)],fl=(e,t,s)=>{if(t._n)return t;const r=Q((...n)=>Ws(t(...n)),s);return r._c=!1,r},yr=(e,t,s)=>{const r=e._ctx;for(const n in e){if(br(n))continue;const o=e[n];if(M(o))t[n]=fl(n,o,r);else if(o!=null){const l=Ws(o);t[n]=()=>l}}},xr=(e,t)=>{const s=Ws(t);e.slots.default=()=>s},ul=(e,t)=>{if(e.vnode.shapeFlag&32){const s=t._;s?(e.slots=N(t),Lt(t,"_",s)):yr(t,e.slots={})}else e.slots={},t&&xr(e,t);Lt(e.slots,ts,1)},al=(e,t,s)=>{const{vnode:r,slots:n}=e;let o=!0,l=K;if(r.shapeFlag&32){const c=t._;c?s&&c===1?o=!1:(G(n,t),!s&&c===1&&delete n._):(o=!t.$stable,yr(t,n)),l=t}else t&&(xr(e,t),l={default:1});if(o)for(const c in n)!br(c)&&!(c in l)&&delete n[c]};function Os(e,t,s,r,n=!1){if(P(e)){e.forEach((E,I)=>Os(E,t&&(P(t)?t[I]:t),s,r,n));return}if(_t(r)&&!n)return;const o=r.shapeFlag&4?Ys(r.component)||r.component.proxy:r.el,l=n?null:o,{i:c,r:u}=e,a=t&&t.r,g=c.refs===K?c.refs={}:c.refs,x=c.setupState;if(a!=null&&a!==u&&(V(a)?(g[a]=null,S(x,a)&&(x[a]=null)):le(a)&&(a.value=null)),M(u))je(u,c,12,[l,g]);else{const E=V(u),I=le(u);if(E||I){const Y=()=>{if(e.f){const $=E?S(x,u)?x[u]:g[u]:u.value;n?P($)&&Fs($,o):P($)?$.includes(o)||$.push(o):E?(g[u]=[o],S(x,u)&&(x[u]=g[u])):(u.value=[o],e.k&&(g[e.k]=u.value))}else E?(g[u]=l,S(x,u)&&(x[u]=l)):I&&(u.value=l,e.k&&(g[e.k]=l))};l?(Y.id=-1,fe(Y,s)):Y()}}}const fe=Bo;function dl(e){return hl(e)}function hl(e,t){const s=gs();s.__VUE__=!0;const{insert:r,remove:n,patchProp:o,createElement:l,createText:c,createComment:u,setText:a,setElementText:g,parentNode:x,nextSibling:E,setScopeId:I=be,insertStaticContent:Y}=e,$=(i,f,d,p=null,h=null,v=null,y=!1,m=null,b=!!f.dynamicChildren)=>{if(i===f)return;i&&!ht(i,f)&&(p=Mt(i),xe(i,h,v,!0),i=null),f.patchFlag===-2&&(b=!1,f.dynamicChildren=null);const{type:_,ref:C,shapeFlag:w}=f;switch(_){case es:X(i,f,d,p);break;case Be:te(i,f,d,p);break;case as:i==null&&se(f,d,p,y);break;case he:Tt(i,f,d,p,h,v,y,m,b);break;default:w&1?Ae(i,f,d,p,h,v,y,m,b):w&6?Pt(i,f,d,p,h,v,y,m,b):(w&64||w&128)&&_.process(i,f,d,p,h,v,y,m,b,Je)}C!=null&&h&&Os(C,i&&i.ref,v,f||i,!f)},X=(i,f,d,p)=>{if(i==null)r(f.el=c(f.children),d,p);else{const h=f.el=i.el;f.children!==i.children&&a(h,f.children)}},te=(i,f,d,p)=>{i==null?r(f.el=u(f.children||""),d,p):f.el=i.el},se=(i,f,d,p)=>{[i.el,i.anchor]=Y(i.children,f,d,p,i.el,i.anchor)},ne=({el:i,anchor:f},d,p)=>{let h;for(;i&&i!==f;)h=E(i),r(i,d,p),i=h;r(f,d,p)},F=({el:i,anchor:f})=>{let d;for(;i&&i!==f;)d=E(i),n(i),i=d;n(f)},Ae=(i,f,d,p,h,v,y,m,b)=>{y=y||f.type==="svg",i==null?ut(f,d,p,h,v,y,m,b):ss(i,f,h,v,y,m,b)},ut=(i,f,d,p,h,v,y,m)=>{let b,_;const{type:C,props:w,shapeFlag:O,transition:T,dirs:A}=i;if(b=i.el=l(i.type,v,w&&w.is,w),O&8?g(b,i.children):O&16&&De(i.children,b,null,p,h,v&&C!=="foreignObject",y,m),A&&Ke(i,null,p,"created"),Ot(b,i,i.scopeId,y,p),w){for(const B in w)B!=="value"&&!Bt(B)&&o(b,B,null,w[B],v,i.children,p,h,Pe);"value"in w&&o(b,"value",null,w.value),(_=w.onVnodeBeforeMount)&&Ee(_,p,i)}A&&Ke(i,null,p,"beforeMount");const H=(!h||h&&!h.pendingBranch)&&T&&!T.persisted;H&&T.beforeEnter(b),r(b,f,d),((_=w&&w.onVnodeMounted)||H||A)&&fe(()=>{_&&Ee(_,p,i),H&&T.enter(b),A&&Ke(i,null,p,"mounted")},h)},Ot=(i,f,d,p,h)=>{if(d&&I(i,d),p)for(let v=0;v{for(let _=b;_{const m=f.el=i.el;let{patchFlag:b,dynamicChildren:_,dirs:C}=f;b|=i.patchFlag&16;const w=i.props||K,O=f.props||K;let T;d&&ke(d,!1),(T=O.onVnodeBeforeUpdate)&&Ee(T,d,f,i),C&&Ke(f,i,d,"beforeUpdate"),d&&ke(d,!0);const A=h&&f.type!=="foreignObject";if(_?He(i.dynamicChildren,_,m,d,p,A,v):y||D(i,f,m,null,d,p,A,v,!1),b>0){if(b&16)at(m,f,w,O,d,p,h);else if(b&2&&w.class!==O.class&&o(m,"class",null,O.class,h),b&4&&o(m,"style",w.style,O.style,h),b&8){const H=f.dynamicProps;for(let B=0;B{T&&Ee(T,d,f,i),C&&Ke(f,i,d,"updated")},p)},He=(i,f,d,p,h,v,y)=>{for(let m=0;m{if(d!==p){if(d!==K)for(const m in d)!Bt(m)&&!(m in p)&&o(i,m,d[m],null,y,f.children,h,v,Pe);for(const m in p){if(Bt(m))continue;const b=p[m],_=d[m];b!==_&&m!=="value"&&o(i,m,_,b,y,f.children,h,v,Pe)}"value"in p&&o(i,"value",d.value,p.value)}},Tt=(i,f,d,p,h,v,y,m,b)=>{const _=f.el=i?i.el:c(""),C=f.anchor=i?i.anchor:c("");let{patchFlag:w,dynamicChildren:O,slotScopeIds:T}=f;T&&(m=m?m.concat(T):T),i==null?(r(_,d,p),r(C,d,p),De(f.children,d,C,h,v,y,m,b)):w>0&&w&64&&O&&i.dynamicChildren?(He(i.dynamicChildren,O,d,h,v,y,m),(f.key!=null||h&&f===h.subTree)&&wr(i,f,!0)):D(i,f,d,C,h,v,y,m,b)},Pt=(i,f,d,p,h,v,y,m,b)=>{f.slotScopeIds=m,i==null?f.shapeFlag&512?h.ctx.activate(f,d,p,y,b):ns(f,d,p,h,v,y,b):Zs(i,f,b)},ns=(i,f,d,p,h,v,y)=>{const m=i.component=wl(i,p,h);if(fr(i)&&(m.ctx.renderer=Je),El(m),m.asyncDep){if(h&&h.registerDep(m,ie),!i.el){const b=m.subTree=L(Be);te(null,b,f,d)}return}ie(m,i,f,d,h,v,y)},Zs=(i,f,d)=>{const p=f.component=i.component;if(So(i,f,d))if(p.asyncDep&&!p.asyncResolved){z(p,f,d);return}else p.next=f,Io(p.update),p.update();else f.el=i.el,p.vnode=f},ie=(i,f,d,p,h,v,y)=>{const m=()=>{if(i.isMounted){let{next:C,bu:w,u:O,parent:T,vnode:A}=i,H=C,B;ke(i,!1),C?(C.el=A.el,z(i,C,y)):C=A,w&&is(w),(B=C.props&&C.props.onVnodeBeforeUpdate)&&Ee(B,T,C,A),ke(i,!0);const J=cs(i),ge=i.subTree;i.subTree=J,$(ge,J,x(ge.el),Mt(ge),i,h,v),C.el=J.el,H===null&&jo(i,J.el),O&&fe(O,h),(B=C.props&&C.props.onVnodeUpdated)&&fe(()=>Ee(B,T,C,A),h)}else{let C;const{el:w,props:O}=f,{bm:T,m:A,parent:H}=i,B=_t(f);if(ke(i,!1),T&&is(T),!B&&(C=O&&O.onVnodeBeforeMount)&&Ee(C,H,f),ke(i,!0),w&&os){const J=()=>{i.subTree=cs(i),os(w,i.subTree,i,h,null)};B?f.type.__asyncLoader().then(()=>!i.isUnmounted&&J()):J()}else{const J=i.subTree=cs(i);$(null,J,d,p,i,h,v),f.el=J.el}if(A&&fe(A,h),!B&&(C=O&&O.onVnodeMounted)){const J=f;fe(()=>Ee(C,H,J),h)}(f.shapeFlag&256||H&&_t(H.vnode)&&H.vnode.shapeFlag&256)&&i.a&&fe(i.a,h),i.isMounted=!0,f=d=p=null}},b=i.effect=new Ss(m,()=>Ks(_),i.scope),_=i.update=()=>b.run();_.id=i.uid,ke(i,!0),_()},z=(i,f,d)=>{f.component=i;const p=i.vnode.props;i.vnode=f,i.next=null,cl(i,f.props,p,d),al(i,f.children,d),ct(),un(),ft()},D=(i,f,d,p,h,v,y,m,b=!1)=>{const _=i&&i.children,C=i?i.shapeFlag:0,w=f.children,{patchFlag:O,shapeFlag:T}=f;if(O>0){if(O&128){It(_,w,d,p,h,v,y,m,b);return}else if(O&256){Le(_,w,d,p,h,v,y,m,b);return}}T&8?(C&16&&Pe(_,h,v),w!==_&&g(d,w)):C&16?T&16?It(_,w,d,p,h,v,y,m,b):Pe(_,h,v,!0):(C&8&&g(d,""),T&16&&De(w,d,p,h,v,y,m,b))},Le=(i,f,d,p,h,v,y,m,b)=>{i=i||Qe,f=f||Qe;const _=i.length,C=f.length,w=Math.min(_,C);let O;for(O=0;OC?Pe(i,h,v,!0,!1,w):De(f,d,p,h,v,y,m,b,w)},It=(i,f,d,p,h,v,y,m,b)=>{let _=0;const C=f.length;let w=i.length-1,O=C-1;for(;_<=w&&_<=O;){const T=i[_],A=f[_]=b?Re(f[_]):Oe(f[_]);if(ht(T,A))$(T,A,d,null,h,v,y,m,b);else break;_++}for(;_<=w&&_<=O;){const T=i[w],A=f[O]=b?Re(f[O]):Oe(f[O]);if(ht(T,A))$(T,A,d,null,h,v,y,m,b);else break;w--,O--}if(_>w){if(_<=O){const T=O+1,A=TO)for(;_<=w;)xe(i[_],h,v,!0),_++;else{const T=_,A=_,H=new Map;for(_=A;_<=O;_++){const de=f[_]=b?Re(f[_]):Oe(f[_]);de.key!=null&&H.set(de.key,_)}let B,J=0;const ge=O-A+1;let Ze=!1,Qs=0;const dt=new Array(ge);for(_=0;_=ge){xe(de,h,v,!0);continue}let we;if(de.key!=null)we=H.get(de.key);else for(B=A;B<=O;B++)if(dt[B-A]===0&&ht(de,f[B])){we=B;break}we===void 0?xe(de,h,v,!0):(dt[we-A]=_+1,we>=Qs?Qs=we:Ze=!0,$(de,f[we],d,null,h,v,y,m,b),J++)}const Gs=Ze?pl(dt):Qe;for(B=Gs.length-1,_=ge-1;_>=0;_--){const de=A+_,we=f[de],en=de+1{const{el:v,type:y,transition:m,children:b,shapeFlag:_}=i;if(_&6){Ue(i.component.subTree,f,d,p);return}if(_&128){i.suspense.move(f,d,p);return}if(_&64){y.move(i,f,d,Je);return}if(y===he){r(v,f,d);for(let w=0;wm.enter(v),h);else{const{leave:w,delayLeave:O,afterLeave:T}=m,A=()=>r(v,f,d),H=()=>{w(v,()=>{A(),T&&T()})};O?O(v,A,H):H()}else r(v,f,d)},xe=(i,f,d,p=!1,h=!1)=>{const{type:v,props:y,ref:m,children:b,dynamicChildren:_,shapeFlag:C,patchFlag:w,dirs:O}=i;if(m!=null&&Os(m,null,d,i,!0),C&256){f.ctx.deactivate(i);return}const T=C&1&&O,A=!_t(i);let H;if(A&&(H=y&&y.onVnodeBeforeUnmount)&&Ee(H,f,i),C&6)Mr(i.component,d,p);else{if(C&128){i.suspense.unmount(d,p);return}T&&Ke(i,null,f,"beforeUnmount"),C&64?i.type.remove(i,f,d,h,Je,p):_&&(v!==he||w>0&&w&64)?Pe(_,f,d,!1,!0):(v===he&&w&384||!h&&C&16)&&Pe(b,f,d),p&&Vs(i)}(A&&(H=y&&y.onVnodeUnmounted)||T)&&fe(()=>{H&&Ee(H,f,i),T&&Ke(i,null,f,"unmounted")},d)},Vs=i=>{const{type:f,el:d,anchor:p,transition:h}=i;if(f===he){Ir(d,p);return}if(f===as){F(i);return}const v=()=>{n(d),h&&!h.persisted&&h.afterLeave&&h.afterLeave()};if(i.shapeFlag&1&&h&&!h.persisted){const{leave:y,delayLeave:m}=h,b=()=>y(d,v);m?m(i.el,v,b):b()}else v()},Ir=(i,f)=>{let d;for(;i!==f;)d=E(i),n(i),i=d;n(f)},Mr=(i,f,d)=>{const{bum:p,scope:h,update:v,subTree:y,um:m}=i;p&&is(p),h.stop(),v&&(v.active=!1,xe(y,i,f,d)),m&&fe(m,f),fe(()=>{i.isUnmounted=!0},f),f&&f.pendingBranch&&!f.isUnmounted&&i.asyncDep&&!i.asyncResolved&&i.suspenseId===f.pendingId&&(f.deps--,f.deps===0&&f.resolve())},Pe=(i,f,d,p=!1,h=!1,v=0)=>{for(let y=v;yi.shapeFlag&6?Mt(i.component.subTree):i.shapeFlag&128?i.suspense.next():E(i.anchor||i.el),Xs=(i,f,d)=>{i==null?f._vnode&&xe(f._vnode,null,null,!0):$(f._vnode||null,i,f,null,null,null,d),un(),nr(),f._vnode=i},Je={p:$,um:xe,m:Ue,r:Vs,mt:ns,mc:De,pc:D,pbc:He,n:Mt,o:e};let rs,os;return t&&([rs,os]=t(Je)),{render:Xs,hydrate:rs,createApp:ol(Xs,rs)}}function ke({effect:e,update:t},s){e.allowRecurse=t.allowRecurse=s}function wr(e,t,s=!1){const r=e.children,n=t.children;if(P(r)&&P(n))for(let o=0;o>1,e[s[c]]0&&(t[r]=s[o-1]),s[o]=r)}}for(o=s.length,l=s[o-1];o-- >0;)s[o]=l,l=t[l];return s}const gl=e=>e.__isTeleport,he=Symbol.for("v-fgt"),es=Symbol.for("v-txt"),Be=Symbol.for("v-cmt"),as=Symbol.for("v-stc"),vt=[];let ve=null;function R(e=!1){vt.push(ve=e?null:[])}function _l(){vt.pop(),ve=vt[vt.length-1]||null}let Et=1;function yn(e){Et+=e}function Er(e){return e.dynamicChildren=Et>0?ve||Qe:null,_l(),Et>0&&ve&&ve.push(e),e}function q(e,t,s,r,n,o){return Er(ee(e,t,s,r,n,o,!0))}function pe(e,t,s,r,n){return Er(L(e,t,s,r,n,!0))}function Cr(e){return e?e.__v_isVNode===!0:!1}function ht(e,t){return e.type===t.type&&e.key===t.key}const ts="__vInternal",Or=({key:e})=>e??null,Ht=({ref:e,ref_key:t,ref_for:s})=>(typeof e=="number"&&(e=""+e),e!=null?V(e)||le(e)||M(e)?{i:ue,r:e,k:t,f:!!s}:e:null);function ee(e,t=null,s=null,r=0,n=null,o=e===he?0:1,l=!1,c=!1){const u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Or(t),ref:t&&Ht(t),scopeId:lr,slotScopeIds:null,children:s,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:r,dynamicProps:n,dynamicChildren:null,appContext:null,ctx:ue};return c?(zs(u,s),o&128&&e.normalize(u)):s&&(u.shapeFlag|=V(s)?8:16),Et>0&&!l&&ve&&(u.patchFlag>0||o&6)&&u.patchFlag!==32&&ve.push(u),u}const L=ml;function ml(e,t=null,s=null,r=0,n=null,o=!1){if((!e||e===Vo)&&(e=Be),Cr(e)){const c=rt(e,t,!0);return s&&zs(c,s),Et>0&&!o&&ve&&(c.shapeFlag&6?ve[ve.indexOf(e)]=c:ve.push(c)),c.patchFlag|=-2,c}if(Pl(e)&&(e=e.__vccOpts),t){t=vl(t);let{class:c,style:u}=t;c&&!V(c)&&(t.class=it(c)),W(u)&&(Vn(u)&&!P(u)&&(u=G({},u)),t.style=Jt(u))}const l=V(e)?1:No(e)?128:gl(e)?64:W(e)?4:M(e)?2:0;return ee(e,t,s,r,n,l,o,!0)}function vl(e){return e?Vn(e)||ts in e?G({},e):e:null}function rt(e,t,s=!1){const{props:r,ref:n,patchFlag:o,children:l}=e,c=t?bl(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&Or(c),ref:t&&t.ref?s&&n?P(n)?n.concat(Ht(t)):[n,Ht(t)]:Ht(t):n,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==he?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&rt(e.ssContent),ssFallback:e.ssFallback&&rt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function j(e=" ",t=0){return L(es,null,e,t)}function Z(e="",t=!1){return t?(R(),pe(Be,null,e)):L(Be,null,e)}function Oe(e){return e==null||typeof e=="boolean"?L(Be):P(e)?L(he,null,e.slice()):typeof e=="object"?Re(e):L(es,null,String(e))}function Re(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:rt(e)}function zs(e,t){let s=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(P(t))s=16;else if(typeof t=="object")if(r&65){const n=t.default;n&&(n._c&&(n._d=!1),zs(e,n()),n._c&&(n._d=!0));return}else{s=32;const n=t._;!n&&!(ts in t)?t._ctx=ue:n===3&&ue&&(ue.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else M(t)?(t={default:t,_ctx:ue},s=32):(t=String(t),r&64?(s=16,t=[j(t)]):s=8);e.children=t,e.shapeFlag|=s}function bl(...e){const t={};for(let s=0;soe=e),qs=e=>{Ve.length>1?Ve.forEach(t=>t(e)):Ve[0](e)};const ot=e=>{qs(e),e.scope.on()},Ye=()=>{oe&&oe.scope.off(),qs(null)};function Tr(e){return e.vnode.shapeFlag&4}let Ct=!1;function El(e,t=!1){Ct=t;const{props:s,children:r}=e.vnode,n=Tr(e);il(e,s,n,t),ul(e,r);const o=n?Cl(e,t):void 0;return Ct=!1,o}function Cl(e,t){const s=e.type;e.accessCache=Object.create(null),e.proxy=Xn(new Proxy(e.ctx,Qo));const{setup:r}=s;if(r){const n=e.setupContext=r.length>1?Tl(e):null;ot(e),ct();const o=je(r,e,0,[e.props,n]);if(ft(),Ye(),Rn(o)){if(o.then(Ye,Ye),t)return o.then(l=>{wn(e,l,t)}).catch(l=>{Vt(l,e,0)});e.asyncDep=o}else wn(e,o,t)}else Pr(e,t)}function wn(e,t,s){M(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:W(t)&&(e.setupState=er(t)),Pr(e,s)}let En;function Pr(e,t,s){const r=e.type;if(!e.render){if(!t&&En&&!r.render){const n=r.template||ks(e).template;if(n){const{isCustomElement:o,compilerOptions:l}=e.appContext.config,{delimiters:c,compilerOptions:u}=r,a=G(G({isCustomElement:o,delimiters:c},l),u);r.render=En(n,a)}}e.render=r.render||be}ot(e),ct(),Go(e),ft(),Ye()}function Ol(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,s){return ae(e,"get","$attrs"),t[s]}}))}function Tl(e){const t=s=>{e.exposed=s||{}};return{get attrs(){return Ol(e)},slots:e.slots,emit:e.emit,expose:t}}function Ys(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(er(Xn(e.exposed)),{get(t,s){if(s in t)return t[s];if(s in mt)return mt[s](e)},has(t,s){return s in t||s in mt}}))}function Pl(e){return M(e)&&"__vccOpts"in e}const Ts=(e,t)=>Co(e,t,Ct),Il=Symbol.for("v-scx"),Ml=()=>Dt(Il),Fl="3.3.4",Al="http://www.w3.org/2000/svg",ze=typeof document<"u"?document:null,Cn=ze&&ze.createElement("template"),$l={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,r)=>{const n=t?ze.createElementNS(Al,e):ze.createElement(e,s?{is:s}:void 0);return e==="select"&&r&&r.multiple!=null&&n.setAttribute("multiple",r.multiple),n},createText:e=>ze.createTextNode(e),createComment:e=>ze.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>ze.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,r,n,o){const l=s?s.previousSibling:t.lastChild;if(n&&(n===o||n.nextSibling))for(;t.insertBefore(n.cloneNode(!0),s),!(n===o||!(n=n.nextSibling)););else{Cn.innerHTML=r?`${e}`:e;const c=Cn.content;if(r){const u=c.firstChild;for(;u.firstChild;)c.appendChild(u.firstChild);c.removeChild(u)}t.insertBefore(c,s)}return[l?l.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}};function Rl(e,t,s){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}function Sl(e,t,s){const r=e.style,n=V(s);if(s&&!n){if(t&&!V(t))for(const o in t)s[o]==null&&Ps(r,o,"");for(const o in s)Ps(r,o,s[o])}else{const o=r.display;n?t!==s&&(r.cssText=s):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=o)}}const On=/\s*!important$/;function Ps(e,t,s){if(P(s))s.forEach(r=>Ps(e,t,r));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const r=jl(e,t);On.test(s)?e.setProperty(lt(r),s.replace(On,""),"important"):e[r]=s}}const Tn=["Webkit","Moz","ms"],ds={};function jl(e,t){const s=ds[t];if(s)return s;let r=st(t);if(r!=="filter"&&r in e)return ds[t]=r;r=Nn(r);for(let n=0;nhs||(Kl.then(()=>hs=0),hs=Date.now());function Wl(e,t){const s=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=s.attached)return;ye(zl(r,s.value),t,5,[r])};return s.value=e,s.attached=kl(),s}function zl(e,t){if(P(t)){const s=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{s.call(e),e._stopped=!0},t.map(r=>n=>!n._stopped&&r&&r(n))}else return t}const Mn=/^on[a-z]/,ql=(e,t,s,r,n=!1,o,l,c,u)=>{t==="class"?Rl(e,r,n):t==="style"?Sl(e,s,r):zt(t)?Ms(t)||Ll(e,t,s,r,l):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Yl(e,t,r,n))?Bl(e,t,r,o,l,c,u):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Nl(e,t,r,n))};function Yl(e,t,s,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Mn.test(t)&&M(s)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Mn.test(t)&&V(s)?!1:t in e}const Jl=G({patchProp:ql},$l);let Fn;function Zl(){return Fn||(Fn=dl(Jl))}const Vl=(...e)=>{const t=Zl().createApp(...e),{mount:s}=t;return t.mount=r=>{const n=Xl(r);if(!n)return;const o=t._component;!M(o)&&!o.render&&!o.template&&(o.template=n.innerHTML),n.innerHTML="";const l=s(n,!1,n instanceof SVGElement);return n instanceof Element&&(n.removeAttribute("v-cloak"),n.setAttribute("data-v-app","")),l},t};function Xl(e){return V(e)?document.querySelector(e):e}const Js=(e,t)=>{const s=e.__vccOpts||e;for(const[r,n]of t)s[r]=n;return s},Ql={},Gl={xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},ei=ee("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18"},null,-1),ti=[ei];function si(e,t){return R(),q("svg",Gl,ti)}const ni=Js(Ql,[["render",si]]),ri={},oi={xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},li=ee("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3"},null,-1),ii=[li];function ci(e,t){return R(),q("svg",oi,ii)}const fi=Js(ri,[["render",ci]]),ui={class:"inline-block text-sm bg-gray-200 rounded-full overflow-hidden relative"},ai=Qt({__name:"Progress",props:{value:{},max:{}},setup(e){return(t,s)=>(R(),q("div",ui,[ee("div",{class:it(["px-2 text-sm transition-[width] duration-500 whitespace-nowrap",{"bg-gray-400/50":t.value/t.max<.8,"bg-orange-300":t.value/t.max>=.8&&t.value/t.max<.9,"bg-red-300":t.value/t.max>=.9}]),style:Jt({width:`${t.value/t.max*100}%`})},[hr(t.$slots,"default")],6)]))}}),di={},hi={class:"inline-block bg-gray-200 px-2 rounded-full text-sm"};function pi(e,t){return R(),q("div",hi,[hr(e.$slots,"default")])}const gi=Js(di,[["render",pi]]),_i=Qt({__name:"StatusIndicator",props:{status:{type:Boolean}},setup(e){return(t,s)=>(R(),q("div",{class:it(["rounded-full inline-block",{"bg-green-400":t.status,"bg-red-500":!t.status}])},null,2))}});function Ce(e,t=2){if(e===0)return"0 B";const s=1024,r=t<0?0:t,n=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],o=Math.floor(Math.log(e)/Math.log(s));return`${Number.parseFloat((e/s**o).toFixed(r))} ${n[o]}`}function mi(e){const t=new Date(e*1e3),s=t.getFullYear(),r=(t.getMonth()+1).toString().padStart(2,"0"),n=t.getDate().toString().padStart(2,"0"),o=t.getHours().toString().padStart(2,"0"),l=t.getMinutes().toString().padStart(2,"0"),c=t.getSeconds().toString().padStart(2,"0");return`${s}/${r}/${n} ${o}:${l}:${c}`}function ps(e){return e.online4||e.online6}function vi(e){return/[\uD800-\uDBFF][\uDC00-\uDFFF]/g.test(e)}const bi={class:"rounded-xl px-4 py-3 transition-all relative bg-gray-100 border border-transparent hover:border-gray-400 hover:shadow-md hover:bg-white duration-300"},yi={class:"absolute right-4 top-4 group flex flex-col items-end"},xi={class:"hidden group-hover:block p-2 rounded-xl border text-sm bg-white z-[9999] mt-1 border-gray-400"},wi={class:"flex gap-2"},Ei={class:"flex items-center gap-1"},Ci={class:"flex items-center gap-1"},Oi={key:0},Ti=ee("br",null,null,-1),Pi={class:"text-lg flex items-center gap-2"},Ii={key:0},Mi=["src","alt"],Fi=["src","alt"],Ai={class:"flex items-center gap-2"},$i={key:0,class:"flex items-center gap-2"},Ri={key:1,class:"flex items-center gap-2"},Si={key:2,class:"flex items-center gap-2"},ji={key:3,class:"flex items-center gap-2"},Ni={key:4,class:"flex items-center gap-2"},Bi={key:5},Di={class:"flex gap-1 flex-wrap mt-1"},Hi=Qt({__name:"ServerItem",props:{server:{}},setup(e){const t=e,s=Ts(()=>{if(!t.server.labels)return{};const n=t.server.labels.split(";"),o={};return n.forEach(l=>{if(l==="")return;const[c,u]=l.split("=");o[c]=u}),o}),r=Ts(()=>!t.server.load&&!t.server.load_1&&!t.server.load_5&&!t.server.load_15);return(n,o)=>{const l=_i,c=gi,u=ai,a=fi,g=ni;return R(),q("div",bi,[ee("div",yi,[L(l,{status:U(ps)(n.server),class:"w-3 h-3"},null,8,["status"]),ee("div",xi,[ee("div",wi,[ee("div",Ei,[j(" IPv4 "),L(l,{status:n.server.online4,class:"w-2 h-2"},null,8,["status"])]),ee("div",Ci,[j(" IPv6 "),L(l,{status:n.server.online6,class:"w-2 h-2"},null,8,["status"])])]),n.server.latest_ts?(R(),q("div",Oi,[j(" 最后上报时间"),Ti,j(" "+k(U(mi)(n.server.latest_ts)),1)])):Z("",!0)])]),ee("div",Pi,[U(vi)(n.server.location)?(R(),q("span",Ii,k(n.server.location),1)):(R(),q("img",{key:1,src:`/image/flags/${n.server.location.toLowerCase()}.svg`,alt:`${n.server.location} flag`,class:"h-4 inline-block rounded-sm"},null,8,Mi)),U(s).os?(R(),q("img",{key:2,src:`/image/os/${U(s).os}.svg`,alt:`${U(s).os} os`,class:"h-4 inline-block rounded-sm"},null,8,Fi)):Z("",!0),j(" "+k(n.server.alias||n.server.name),1)]),ee("div",null,[j(" 运行时间 "),ee("span",{class:it({"text-red-500":!U(ps)(n.server)})},k(U(ps)(n.server)?n.server.uptime:"离线"),3)]),ee("div",Ai,[j(" 负载 "),U(r)?(R(),pe(c,{key:0},{default:Q(()=>[j(" 无数据 ")]),_:1})):Z("",!0),n.server.load?(R(),pe(c,{key:1},{default:Q(()=>[j(k(n.server.load),1)]),_:1})):Z("",!0),n.server.load_1?(R(),pe(c,{key:2},{default:Q(()=>[j(k(n.server.load_1),1)]),_:1})):Z("",!0),n.server.load_5?(R(),pe(c,{key:3},{default:Q(()=>[j(k(n.server.load_5),1)]),_:1})):Z("",!0),n.server.load_15?(R(),pe(c,{key:4},{default:Q(()=>[j(k(n.server.load_15),1)]),_:1})):Z("",!0)]),n.server.cpu?(R(),q("div",$i,[j(" CPU "),L(u,{value:n.server.cpu,max:100,text:`${n.server.cpu}%`,class:"flex-1"},{default:Q(()=>[j(k(n.server.cpu)+"% ",1)]),_:1},8,["value","text"])])):Z("",!0),n.server.memory_total?(R(),q("div",Ri,[j(" 内存 "),L(u,{value:n.server.memory_used,max:n.server.memory_total,class:"flex-1"},{default:Q(()=>[j(k(U(Ce)(n.server.memory_used*1024))+" / "+k(U(Ce)(n.server.memory_total*1024)),1)]),_:1},8,["value","max"])])):Z("",!0),n.server.hdd_total?(R(),q("div",Si,[j(" 硬盘 "),L(u,{value:n.server.hdd_used,max:n.server.hdd_total,class:"flex-1"},{default:Q(()=>[j(k(U(Ce)(n.server.hdd_used*1024*1024))+" / "+k(U(Ce)(n.server.hdd_total*1024*1024)),1)]),_:1},8,["value","max"])])):Z("",!0),n.server.network_rx?(R(),q("div",ji,[j(" 网络 "),L(c,{class:"flex items-center"},{default:Q(()=>[L(a,{class:"w-4 h-4"}),j(k(U(Ce)(n.server.network_rx,1))+"/s ",1)]),_:1}),L(c,{class:"flex items-center"},{default:Q(()=>[L(g,{class:"w-4 h-4"}),j(k(U(Ce)(n.server.network_tx,1))+"/s ",1)]),_:1})])):Z("",!0),n.server.network_in?(R(),q("div",Ni,[j(" 流量 "),L(c,{class:"flex items-center"},{default:Q(()=>[L(a,{class:"w-4 h-4"}),j(k(U(Ce)(n.server.network_in,1)),1)]),_:1}),L(c,{class:"flex items-center"},{default:Q(()=>[L(g,{class:"w-4 h-4"}),j(k(U(Ce)(n.server.network_out,1)),1)]),_:1})])):Z("",!0),n.server.swap_total?(R(),q("div",Bi,[j(" SWAP "),L(c,null,{default:Q(()=>[j(k(U(Ce)(n.server.swap_used*1024))+" / "+k(U(Ce)(n.server.swap_total*1024)),1)]),_:1})])):Z("",!0),ee("div",Di,[n.server.tcp_count?(R(),pe(c,{key:0},{default:Q(()=>[j(" TCP "+k(n.server.tcp_count),1)]),_:1})):Z("",!0),n.server.udp_count?(R(),pe(c,{key:1},{default:Q(()=>[j(" UDP "+k(n.server.udp_count),1)]),_:1})):Z("",!0),n.server.process_count?(R(),pe(c,{key:2},{default:Q(()=>[j(" 进程 "+k(n.server.process_count),1)]),_:1})):Z("",!0),n.server.thread_count?(R(),pe(c,{key:3},{default:Q(()=>[j(" 线程 "+k(n.server.thread_count),1)]),_:1})):Z("",!0)])])}}}),Li={key:0,class:"w-fit mx-auto my-2"},Ui={key:1,class:"w-fit mx-auto my-2"},Ki={key:2,class:"flex flex-wrap gap-x-4 gap-y-3"},ki=ee("div",{class:"h-16"},null,-1),An="/json/stats.json",Wi=Qt({__name:"App",setup(e){const t=jt(),s=jt(!0),r=jt(!1),n=jt(!1);ar(()=>{fetch(An).then(l=>l.json()).then(l=>{t.value=l,setInterval(()=>{o()},500)}).catch(()=>{r.value=!0}).finally(()=>{s.value=!1})});function o(){n.value||(n.value=!0,fetch(An).then(l=>l.json()).then(l=>{t.value=l,r.value=!1}).catch(()=>{r.value=!0}).finally(()=>{n.value=!1}))}return(l,c)=>{const u=Hi;return R(),q(he,null,[U(s)?(R(),q("div",Li," 加载中 ")):Z("",!0),U(r)?(R(),q("div",Ui," 数据加载失败,请尝试刷新页面或检查 ServerStatus 服务端状态 ")):Z("",!0),U(t)?(R(),q("div",Ki,[(R(!0),q(he,null,Xo(U(t).servers,(a,g)=>(R(),pe(u,{key:g,server:a,class:"flex-1 min-w-[300px]"},null,8,["server"]))),128))])):Z("",!0),ki],64)}}});const zi=Vl(Wi);zi.mount("#app"); diff --git a/web/assets/index-e069a4f0.js b/web/assets/index-e069a4f0.js new file mode 100644 index 00000000..e46b9844 --- /dev/null +++ b/web/assets/index-e069a4f0.js @@ -0,0 +1 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const l of o.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&s(l)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();function Pn(e,t){const n=Object.create(null),s=e.split(",");for(let r=0;r!!n[r.toLowerCase()]:r=>!!n[r]}const L={},Ve=[],me=()=>{},Fr=()=>!1,Ar=/^on[^a-z]/,Wt=e=>Ar.test(e),In=e=>e.startsWith("onUpdate:"),X=Object.assign,Mn=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},$r=Object.prototype.hasOwnProperty,R=(e,t)=>$r.call(e,t),P=Array.isArray,Xe=e=>zt(e)==="[object Map]",As=e=>zt(e)==="[object Set]",M=e=>typeof e=="function",J=e=>typeof e=="string",Fn=e=>typeof e=="symbol",W=e=>e!==null&&typeof e=="object",$s=e=>W(e)&&M(e.then)&&M(e.catch),Rs=Object.prototype.toString,zt=e=>Rs.call(e),Rr=e=>zt(e).slice(8,-1),Ss=e=>zt(e)==="[object Object]",An=e=>J(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,jt=Pn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),kt=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Sr=/-(\w)/g,et=kt(e=>e.replace(Sr,(t,n)=>n?n.toUpperCase():"")),jr=/\B([A-Z])/g,rt=kt(e=>e.replace(jr,"-$1").toLowerCase()),js=kt(e=>e.charAt(0).toUpperCase()+e.slice(1)),rn=kt(e=>e?`on${js(e)}`:""),bt=(e,t)=>!Object.is(e,t),on=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Nr=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let ts;const gn=()=>ts||(ts=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function qt(e){if(P(e)){const t={};for(let n=0;n{if(n){const s=n.split(Dr);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function ot(e){let t="";if(J(e))t=e;else if(P(e))for(let n=0;nJ(e)?e:e==null?"":P(e)||W(e)&&(e.toString===Rs||!M(e.toString))?JSON.stringify(e,Bs,2):String(e),Bs=(e,t)=>t&&t.__v_isRef?Bs(e,t.value):Xe(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,r])=>(n[`${s} =>`]=r,n),{})}:As(t)?{[`Set(${t.size})`]:[...t.values()]}:W(t)&&!P(t)&&!Ss(t)?String(t):t;let pe;class Wr{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=pe,!t&&pe&&(this.index=(pe.scopes||(pe.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=pe;try{return pe=this,t()}finally{pe=n}}}on(){pe=this}off(){pe=this.parent}stop(t){if(this._active){let n,s;for(n=0,s=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},Ds=e=>(e.w&Se)>0,Hs=e=>(e.n&Se)>0,qr=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let s=0;s{(_==="length"||_>=u)&&c.push(a)})}else switch(n!==void 0&&c.push(l.get(n)),t){case"add":P(e)?An(n)&&c.push(l.get("length")):(c.push(l.get(ze)),Xe(e)&&c.push(l.get(bn)));break;case"delete":P(e)||(c.push(l.get(ze)),Xe(e)&&c.push(l.get(bn)));break;case"set":Xe(e)&&c.push(l.get(ze));break}if(c.length===1)c[0]&&vn(c[0]);else{const u=[];for(const a of c)a&&u.push(...a);vn($n(u))}}function vn(e,t){const n=P(e)?e:[...e];for(const s of n)s.computed&&ss(s);for(const s of n)s.computed||ss(s)}function ss(e,t){(e!==ge||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}const Jr=Pn("__proto__,__v_isRef,__isVue"),Ks=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Fn)),Zr=Sn(),Vr=Sn(!1,!0),Xr=Sn(!0),rs=Qr();function Qr(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const s=j(this);for(let o=0,l=this.length;o{e[t]=function(...n){lt();const s=j(this)[t].apply(this,n);return it(),s}}),e}function Gr(e){const t=j(this);return ue(t,"has",e),t.hasOwnProperty(e)}function Sn(e=!1,t=!1){return function(s,r,o){if(r==="__v_isReactive")return!e;if(r==="__v_isReadonly")return e;if(r==="__v_isShallow")return t;if(r==="__v_raw"&&o===(e?t?_o:Ys:t?qs:ks).get(s))return s;const l=P(s);if(!e){if(l&&R(rs,r))return Reflect.get(rs,r,o);if(r==="hasOwnProperty")return Gr}const c=Reflect.get(s,r,o);return(Fn(r)?Ks.has(r):Jr(r))||(e||ue(s,"get",r),t)?c:re(c)?l&&An(r)?c:c.value:W(c)?e?Js(c):Bn(c):c}}const eo=Ws(),to=Ws(!0);function Ws(e=!1){return function(n,s,r,o){let l=n[s];if(tt(l)&&re(l)&&!re(r))return!1;if(!e&&(!Ht(r)&&!tt(r)&&(l=j(l),r=j(r)),!P(n)&&re(l)&&!re(r)))return l.value=r,!0;const c=P(n)&&An(s)?Number(s)e,Yt=e=>Reflect.getPrototypeOf(e);function Mt(e,t,n=!1,s=!1){e=e.__v_raw;const r=j(e),o=j(t);n||(t!==o&&ue(r,"get",t),ue(r,"get",o));const{has:l}=Yt(r),c=s?jn:n?Hn:vt;if(l.call(r,t))return c(e.get(t));if(l.call(r,o))return c(e.get(o));e!==r&&e.get(t)}function Ft(e,t=!1){const n=this.__v_raw,s=j(n),r=j(e);return t||(e!==r&&ue(s,"has",e),ue(s,"has",r)),e===r?n.has(e):n.has(e)||n.has(r)}function At(e,t=!1){return e=e.__v_raw,!t&&ue(j(e),"iterate",ze),Reflect.get(e,"size",e)}function os(e){e=j(e);const t=j(this);return Yt(t).has.call(t,e)||(t.add(e),Pe(t,"add",e,e)),this}function ls(e,t){t=j(t);const n=j(this),{has:s,get:r}=Yt(n);let o=s.call(n,e);o||(e=j(e),o=s.call(n,e));const l=r.call(n,e);return n.set(e,t),o?bt(t,l)&&Pe(n,"set",e,t):Pe(n,"add",e,t),this}function is(e){const t=j(this),{has:n,get:s}=Yt(t);let r=n.call(t,e);r||(e=j(e),r=n.call(t,e)),s&&s.call(t,e);const o=t.delete(e);return r&&Pe(t,"delete",e,void 0),o}function cs(){const e=j(this),t=e.size!==0,n=e.clear();return t&&Pe(e,"clear",void 0,void 0),n}function $t(e,t){return function(s,r){const o=this,l=o.__v_raw,c=j(l),u=t?jn:e?Hn:vt;return!e&&ue(c,"iterate",ze),l.forEach((a,_)=>s.call(r,u(a),u(_),o))}}function Rt(e,t,n){return function(...s){const r=this.__v_raw,o=j(r),l=Xe(o),c=e==="entries"||e===Symbol.iterator&&l,u=e==="keys"&&l,a=r[e](...s),_=n?jn:t?Hn:vt;return!t&&ue(o,"iterate",u?bn:ze),{next(){const{value:y,done:E}=a.next();return E?{value:y,done:E}:{value:c?[_(y[0]),_(y[1])]:_(y),done:E}},[Symbol.iterator](){return this}}}}function Fe(e){return function(...t){return e==="delete"?!1:this}}function io(){const e={get(o){return Mt(this,o)},get size(){return At(this)},has:Ft,add:os,set:ls,delete:is,clear:cs,forEach:$t(!1,!1)},t={get(o){return Mt(this,o,!1,!0)},get size(){return At(this)},has:Ft,add:os,set:ls,delete:is,clear:cs,forEach:$t(!1,!0)},n={get(o){return Mt(this,o,!0)},get size(){return At(this,!0)},has(o){return Ft.call(this,o,!0)},add:Fe("add"),set:Fe("set"),delete:Fe("delete"),clear:Fe("clear"),forEach:$t(!0,!1)},s={get(o){return Mt(this,o,!0,!0)},get size(){return At(this,!0)},has(o){return Ft.call(this,o,!0)},add:Fe("add"),set:Fe("set"),delete:Fe("delete"),clear:Fe("clear"),forEach:$t(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(o=>{e[o]=Rt(o,!1,!1),n[o]=Rt(o,!0,!1),t[o]=Rt(o,!1,!0),s[o]=Rt(o,!0,!0)}),[e,n,t,s]}const[co,fo,uo,ao]=io();function Nn(e,t){const n=t?e?ao:uo:e?fo:co;return(s,r,o)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?s:Reflect.get(R(n,r)&&r in s?n:s,r,o)}const ho={get:Nn(!1,!1)},po={get:Nn(!1,!0)},go={get:Nn(!0,!1)},ks=new WeakMap,qs=new WeakMap,Ys=new WeakMap,_o=new WeakMap;function mo(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function bo(e){return e.__v_skip||!Object.isExtensible(e)?0:mo(Rr(e))}function Bn(e){return tt(e)?e:Dn(e,!1,zs,ho,ks)}function vo(e){return Dn(e,!1,lo,po,qs)}function Js(e){return Dn(e,!0,oo,go,Ys)}function Dn(e,t,n,s,r){if(!W(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const o=r.get(e);if(o)return o;const l=bo(e);if(l===0)return e;const c=new Proxy(e,l===2?s:n);return r.set(e,c),c}function Qe(e){return tt(e)?Qe(e.__v_raw):!!(e&&e.__v_isReactive)}function tt(e){return!!(e&&e.__v_isReadonly)}function Ht(e){return!!(e&&e.__v_isShallow)}function Zs(e){return Qe(e)||tt(e)}function j(e){const t=e&&e.__v_raw;return t?j(t):e}function Vs(e){return Dt(e,"__v_skip",!0),e}const vt=e=>W(e)?Bn(e):e,Hn=e=>W(e)?Js(e):e;function Xs(e){$e&&ge&&(e=j(e),Us(e.dep||(e.dep=$n())))}function Qs(e,t){e=j(e);const n=e.dep;n&&vn(n)}function re(e){return!!(e&&e.__v_isRef===!0)}function ln(e){return xo(e,!1)}function xo(e,t){return re(e)?e:new yo(e,t)}class yo{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:j(t),this._value=n?t:vt(t)}get value(){return Xs(this),this._value}set value(t){const n=this.__v_isShallow||Ht(t)||tt(t);t=n?t:j(t),bt(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:vt(t),Qs(this))}}function U(e){return re(e)?e.value:e}const wo={get:(e,t,n)=>U(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const r=e[t];return re(r)&&!re(n)?(r.value=n,!0):Reflect.set(e,t,n,s)}};function Gs(e){return Qe(e)?e:new Proxy(e,wo)}class Eo{constructor(t,n,s,r){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Rn(t,()=>{this._dirty||(this._dirty=!0,Qs(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!r,this.__v_isReadonly=s}get value(){const t=j(this);return Xs(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function Co(e,t,n=!1){let s,r;const o=M(e);return o?(s=e,r=me):(s=e.get,r=e.set),new Eo(s,r,o||!r,n)}function Re(e,t,n,s){let r;try{r=s?e(...s):e()}catch(o){Jt(o,t,n)}return r}function be(e,t,n,s){if(M(e)){const o=Re(e,t,n,s);return o&&$s(o)&&o.catch(l=>{Jt(l,t,n)}),o}const r=[];for(let o=0;o>>1;yt(ne[s])Ce&&ne.splice(t,1)}function Mo(e){P(e)?Ge.push(...e):(!Te||!Te.includes(e,e.allowRecurse?Ke+1:Ke))&&Ge.push(e),tr()}function fs(e,t=xt?Ce+1:0){for(;tyt(n)-yt(s)),Ke=0;Kee.id==null?1/0:e.id,Fo=(e,t)=>{const n=yt(e)-yt(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function sr(e){xn=!1,xt=!0,ne.sort(Fo);const t=me;try{for(Ce=0;CeJ(I)?I.trim():I)),y&&(r=n.map(Nr))}let c,u=s[c=rn(t)]||s[c=rn(et(t))];!u&&o&&(u=s[c=rn(rt(t))]),u&&be(u,e,6,r);const a=s[c+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[c])return;e.emitted[c]=!0,be(a,e,6,r)}}function rr(e,t,n=!1){const s=t.emitsCache,r=s.get(e);if(r!==void 0)return r;const o=e.emits;let l={},c=!1;if(!M(e)){const u=a=>{const _=rr(a,t,!0);_&&(c=!0,X(l,_))};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}return!o&&!c?(W(e)&&s.set(e,null),null):(P(o)?o.forEach(u=>l[u]=null):X(l,o),W(e)&&s.set(e,l),l)}function Zt(e,t){return!e||!Wt(t)?!1:(t=t.slice(2).replace(/Once$/,""),R(e,t[0].toLowerCase()+t.slice(1))||R(e,rt(t))||R(e,t))}let fe=null,or=null;function Lt(e){const t=fe;return fe=e,or=e&&e.type.__scopeId||null,t}function te(e,t=fe,n){if(!t||e._n)return e;const s=(...r)=>{s._d&&vs(-1);const o=Lt(t);let l;try{l=e(...r)}finally{Lt(o),s._d&&vs(1)}return l};return s._n=!0,s._c=!0,s._d=!0,s}function cn(e){const{type:t,vnode:n,proxy:s,withProxy:r,props:o,propsOptions:[l],slots:c,attrs:u,emit:a,render:_,renderCache:y,data:E,setupState:I,ctx:q,inheritAttrs:$}=e;let Z,Q;const G=Lt(e);try{if(n.shapeFlag&4){const F=r||s;Z=Ee(_.call(F,F,y,o,I,E,q)),Q=u}else{const F=t;Z=Ee(F.length>1?F(o,{attrs:u,slots:c,emit:a}):F(o,null)),Q=t.props?u:$o(u)}}catch(F){_t.length=0,Jt(F,e,1),Z=S(je)}let ee=Z;if(Q&&$!==!1){const F=Object.keys(Q),{shapeFlag:Me}=ee;F.length&&Me&7&&(l&&F.some(In)&&(Q=Ro(Q,l)),ee=nt(ee,Q))}return n.dirs&&(ee=nt(ee),ee.dirs=ee.dirs?ee.dirs.concat(n.dirs):n.dirs),n.transition&&(ee.transition=n.transition),Z=ee,Lt(G),Z}const $o=e=>{let t;for(const n in e)(n==="class"||n==="style"||Wt(n))&&((t||(t={}))[n]=e[n]);return t},Ro=(e,t)=>{const n={};for(const s in e)(!In(s)||!(s.slice(9)in t))&&(n[s]=e[s]);return n};function So(e,t,n){const{props:s,children:r,component:o}=e,{props:l,children:c,patchFlag:u}=t,a=o.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&u>=0){if(u&1024)return!0;if(u&16)return s?us(s,l,a):!!l;if(u&8){const _=t.dynamicProps;for(let y=0;y<_.length;y++){const E=_[y];if(l[E]!==s[E]&&!Zt(a,E))return!0}}}else return(r||c)&&(!c||!c.$stable)?!0:s===l?!1:s?l?us(s,l,a):!0:!!l;return!1}function us(e,t,n){const s=Object.keys(t);if(s.length!==Object.keys(e).length)return!0;for(let r=0;re.__isSuspense;function Bo(e,t){t&&t.pendingBranch?P(e)?t.effects.push(...e):t.effects.push(e):Mo(e)}const St={};function fn(e,t,n){return lr(e,t,n)}function lr(e,t,{immediate:n,deep:s,flush:r,onTrack:o,onTrigger:l}=L){var c;const u=kr()===((c=se)==null?void 0:c.scope)?se:null;let a,_=!1,y=!1;if(re(e)?(a=()=>e.value,_=Ht(e)):Qe(e)?(a=()=>e,s=!0):P(e)?(y=!0,_=e.some(F=>Qe(F)||Ht(F)),a=()=>e.map(F=>{if(re(F))return F.value;if(Qe(F))return Ze(F);if(M(F))return Re(F,u,2)})):M(e)?t?a=()=>Re(e,u,2):a=()=>{if(!(u&&u.isUnmounted))return E&&E(),be(e,u,3,[I])}:a=me,t&&s){const F=a;a=()=>Ze(F())}let E,I=F=>{E=G.onStop=()=>{Re(F,u,4)}},q;if(Et)if(I=me,t?n&&be(t,u,3,[a(),y?[]:void 0,I]):a(),r==="sync"){const F=Ml();q=F.__watcherHandles||(F.__watcherHandles=[])}else return me;let $=y?new Array(e.length).fill(St):St;const Z=()=>{if(G.active)if(t){const F=G.run();(s||_||(y?F.some((Me,ct)=>bt(Me,$[ct])):bt(F,$)))&&(E&&E(),be(t,u,3,[F,$===St?void 0:y&&$[0]===St?[]:$,I]),$=F)}else G.run()};Z.allowRecurse=!!t;let Q;r==="sync"?Q=Z:r==="post"?Q=()=>ce(Z,u&&u.suspense):(Z.pre=!0,u&&(Z.id=u.uid),Q=()=>Un(Z));const G=new Rn(a,Q);t?n?Z():$=G.run():r==="post"?ce(G.run.bind(G),u&&u.suspense):G.run();const ee=()=>{G.stop(),u&&u.scope&&Mn(u.scope.effects,G)};return q&&q.push(ee),ee}function Do(e,t,n){const s=this.proxy,r=J(e)?e.includes(".")?ir(s,e):()=>s[e]:e.bind(s,s);let o;M(t)?o=t:(o=t.handler,n=t);const l=se;st(this);const c=lr(r,o.bind(s),n);return l?st(l):ke(),c}function ir(e,t){const n=t.split(".");return()=>{let s=e;for(let r=0;r{Ze(n,t)});else if(Ss(e))for(const n in e)Ze(e[n],t);return e}function Le(e,t,n,s){const r=e.dirs,o=t&&t.dirs;for(let l=0;lX({name:e.name},t,{setup:e}))():e}const pt=e=>!!e.type.__asyncLoader,cr=e=>e.type.__isKeepAlive;function Ho(e,t){fr(e,"a",t)}function Lo(e,t){fr(e,"da",t)}function fr(e,t,n=se){const s=e.__wdc||(e.__wdc=()=>{let r=n;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(Xt(t,s,n),n){let r=n.parent;for(;r&&r.parent;)cr(r.parent.vnode)&&Uo(s,t,n,r),r=r.parent}}function Uo(e,t,n,s){const r=Xt(t,e,s,!0);ar(()=>{Mn(s[t],r)},n)}function Xt(e,t,n=se,s=!1){if(n){const r=n[e]||(n[e]=[]),o=t.__weh||(t.__weh=(...l)=>{if(n.isUnmounted)return;lt(),st(n);const c=be(t,n,e,l);return ke(),it(),c});return s?r.unshift(o):r.push(o),o}}const Ie=e=>(t,n=se)=>(!Et||e==="sp")&&Xt(e,(...s)=>t(...s),n),Ko=Ie("bm"),ur=Ie("m"),Wo=Ie("bu"),zo=Ie("u"),ko=Ie("bum"),ar=Ie("um"),qo=Ie("sp"),Yo=Ie("rtg"),Jo=Ie("rtc");function Zo(e,t=se){Xt("ec",e,t)}const Vo=Symbol.for("v-ndc");function Xo(e,t,n,s){let r;const o=n&&n[s];if(P(e)||J(e)){r=new Array(e.length);for(let l=0,c=e.length;lt(l,c,void 0,o&&o[c]));else{const l=Object.keys(e);r=new Array(l.length);for(let c=0,u=l.length;cEr(t)?!(t.type===je||t.type===de&&!hr(t.children)):!0)?e:null}const yn=e=>e?Or(e)?Yn(e)||e.proxy:yn(e.parent):null,gt=X(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>yn(e.parent),$root:e=>yn(e.root),$emit:e=>e.emit,$options:e=>Kn(e),$forceUpdate:e=>e.f||(e.f=()=>Un(e.update)),$nextTick:e=>e.n||(e.n=To.bind(e.proxy)),$watch:e=>Do.bind(e)}),un=(e,t)=>e!==L&&!e.__isScriptSetup&&R(e,t),Qo={get({_:e},t){const{ctx:n,setupState:s,data:r,props:o,accessCache:l,type:c,appContext:u}=e;let a;if(t[0]!=="$"){const I=l[t];if(I!==void 0)switch(I){case 1:return s[t];case 2:return r[t];case 4:return n[t];case 3:return o[t]}else{if(un(s,t))return l[t]=1,s[t];if(r!==L&&R(r,t))return l[t]=2,r[t];if((a=e.propsOptions[0])&&R(a,t))return l[t]=3,o[t];if(n!==L&&R(n,t))return l[t]=4,n[t];wn&&(l[t]=0)}}const _=gt[t];let y,E;if(_)return t==="$attrs"&&ue(e,"get",t),_(e);if((y=c.__cssModules)&&(y=y[t]))return y;if(n!==L&&R(n,t))return l[t]=4,n[t];if(E=u.config.globalProperties,R(E,t))return E[t]},set({_:e},t,n){const{data:s,setupState:r,ctx:o}=e;return un(r,t)?(r[t]=n,!0):s!==L&&R(s,t)?(s[t]=n,!0):R(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(o[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:s,appContext:r,propsOptions:o}},l){let c;return!!n[l]||e!==L&&R(e,l)||un(t,l)||(c=o[0])&&R(c,l)||R(s,l)||R(gt,l)||R(r.config.globalProperties,l)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:R(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function as(e){return P(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let wn=!0;function Go(e){const t=Kn(e),n=e.proxy,s=e.ctx;wn=!1,t.beforeCreate&&ds(t.beforeCreate,e,"bc");const{data:r,computed:o,methods:l,watch:c,provide:u,inject:a,created:_,beforeMount:y,mounted:E,beforeUpdate:I,updated:q,activated:$,deactivated:Z,beforeDestroy:Q,beforeUnmount:G,destroyed:ee,unmounted:F,render:Me,renderTracked:ct,renderTriggered:Ct,errorCaptured:Ne,serverPrefetch:en,expose:Be,inheritAttrs:ft,components:Ot,directives:Tt,filters:tn}=t;if(a&&el(a,s,null),l)for(const z in l){const D=l[z];M(D)&&(s[z]=D.bind(n))}if(r){const z=r.call(n,n);W(z)&&(e.data=Bn(z))}if(wn=!0,o)for(const z in o){const D=o[z],De=M(D)?D.bind(n,n):M(D.get)?D.get.bind(n,n):me,Pt=!M(D)&&M(D.set)?D.set.bind(n):me,He=Pr({get:De,set:Pt});Object.defineProperty(s,z,{enumerable:!0,configurable:!0,get:()=>He.value,set:ve=>He.value=ve})}if(c)for(const z in c)pr(c[z],s,n,z);if(u){const z=M(u)?u.call(n):u;Reflect.ownKeys(z).forEach(D=>{ll(D,z[D])})}_&&ds(_,e,"c");function oe(z,D){P(D)?D.forEach(De=>z(De.bind(n))):D&&z(D.bind(n))}if(oe(Ko,y),oe(ur,E),oe(Wo,I),oe(zo,q),oe(Ho,$),oe(Lo,Z),oe(Zo,Ne),oe(Jo,ct),oe(Yo,Ct),oe(ko,G),oe(ar,F),oe(qo,en),P(Be))if(Be.length){const z=e.exposed||(e.exposed={});Be.forEach(D=>{Object.defineProperty(z,D,{get:()=>n[D],set:De=>n[D]=De})})}else e.exposed||(e.exposed={});Me&&e.render===me&&(e.render=Me),ft!=null&&(e.inheritAttrs=ft),Ot&&(e.components=Ot),Tt&&(e.directives=Tt)}function el(e,t,n=me){P(e)&&(e=En(e));for(const s in e){const r=e[s];let o;W(r)?"default"in r?o=Nt(r.from||s,r.default,!0):o=Nt(r.from||s):o=Nt(r),re(o)?Object.defineProperty(t,s,{enumerable:!0,configurable:!0,get:()=>o.value,set:l=>o.value=l}):t[s]=o}}function ds(e,t,n){be(P(e)?e.map(s=>s.bind(t.proxy)):e.bind(t.proxy),t,n)}function pr(e,t,n,s){const r=s.includes(".")?ir(n,s):()=>n[s];if(J(e)){const o=t[e];M(o)&&fn(r,o)}else if(M(e))fn(r,e.bind(n));else if(W(e))if(P(e))e.forEach(o=>pr(o,t,n,s));else{const o=M(e.handler)?e.handler.bind(n):t[e.handler];M(o)&&fn(r,o,e)}}function Kn(e){const t=e.type,{mixins:n,extends:s}=t,{mixins:r,optionsCache:o,config:{optionMergeStrategies:l}}=e.appContext,c=o.get(t);let u;return c?u=c:!r.length&&!n&&!s?u=t:(u={},r.length&&r.forEach(a=>Ut(u,a,l,!0)),Ut(u,t,l)),W(t)&&o.set(t,u),u}function Ut(e,t,n,s=!1){const{mixins:r,extends:o}=t;o&&Ut(e,o,n,!0),r&&r.forEach(l=>Ut(e,l,n,!0));for(const l in t)if(!(s&&l==="expose")){const c=tl[l]||n&&n[l];e[l]=c?c(e[l],t[l]):t[l]}return e}const tl={data:hs,props:ps,emits:ps,methods:ht,computed:ht,beforeCreate:le,created:le,beforeMount:le,mounted:le,beforeUpdate:le,updated:le,beforeDestroy:le,beforeUnmount:le,destroyed:le,unmounted:le,activated:le,deactivated:le,errorCaptured:le,serverPrefetch:le,components:ht,directives:ht,watch:sl,provide:hs,inject:nl};function hs(e,t){return t?e?function(){return X(M(e)?e.call(this,this):e,M(t)?t.call(this,this):t)}:t:e}function nl(e,t){return ht(En(e),En(t))}function En(e){if(P(e)){const t={};for(let n=0;n1)return n&&M(t)?t.call(s&&s.proxy):t}}function il(e,t,n,s=!1){const r={},o={};Dt(o,Gt,1),e.propsDefaults=Object.create(null),_r(e,t,r,o);for(const l in e.propsOptions[0])l in r||(r[l]=void 0);n?e.props=s?r:vo(r):e.type.props?e.props=r:e.props=o,e.attrs=o}function cl(e,t,n,s){const{props:r,attrs:o,vnode:{patchFlag:l}}=e,c=j(r),[u]=e.propsOptions;let a=!1;if((s||l>0)&&!(l&16)){if(l&8){const _=e.vnode.dynamicProps;for(let y=0;y<_.length;y++){let E=_[y];if(Zt(e.emitsOptions,E))continue;const I=t[E];if(u)if(R(o,E))I!==o[E]&&(o[E]=I,a=!0);else{const q=et(E);r[q]=Cn(u,c,q,I,e,!1)}else I!==o[E]&&(o[E]=I,a=!0)}}}else{_r(e,t,r,o)&&(a=!0);let _;for(const y in c)(!t||!R(t,y)&&((_=rt(y))===y||!R(t,_)))&&(u?n&&(n[y]!==void 0||n[_]!==void 0)&&(r[y]=Cn(u,c,y,void 0,e,!0)):delete r[y]);if(o!==c)for(const y in o)(!t||!R(t,y))&&(delete o[y],a=!0)}a&&Pe(e,"set","$attrs")}function _r(e,t,n,s){const[r,o]=e.propsOptions;let l=!1,c;if(t)for(let u in t){if(jt(u))continue;const a=t[u];let _;r&&R(r,_=et(u))?!o||!o.includes(_)?n[_]=a:(c||(c={}))[_]=a:Zt(e.emitsOptions,u)||(!(u in s)||a!==s[u])&&(s[u]=a,l=!0)}if(o){const u=j(n),a=c||L;for(let _=0;_{u=!0;const[E,I]=mr(y,t,!0);X(l,E),I&&c.push(...I)};!n&&t.mixins.length&&t.mixins.forEach(_),e.extends&&_(e.extends),e.mixins&&e.mixins.forEach(_)}if(!o&&!u)return W(e)&&s.set(e,Ve),Ve;if(P(o))for(let _=0;_-1,I[1]=$<0||q<$,(q>-1||R(I,"default"))&&c.push(y)}}}const a=[l,c];return W(e)&&s.set(e,a),a}function gs(e){return e[0]!=="$"}function _s(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function ms(e,t){return _s(e)===_s(t)}function bs(e,t){return P(t)?t.findIndex(n=>ms(n,e)):M(t)&&ms(t,e)?0:-1}const br=e=>e[0]==="_"||e==="$stable",Wn=e=>P(e)?e.map(Ee):[Ee(e)],fl=(e,t,n)=>{if(t._n)return t;const s=te((...r)=>Wn(t(...r)),n);return s._c=!1,s},vr=(e,t,n)=>{const s=e._ctx;for(const r in e){if(br(r))continue;const o=e[r];if(M(o))t[r]=fl(r,o,s);else if(o!=null){const l=Wn(o);t[r]=()=>l}}},xr=(e,t)=>{const n=Wn(t);e.slots.default=()=>n},ul=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=j(t),Dt(t,"_",n)):vr(t,e.slots={})}else e.slots={},t&&xr(e,t);Dt(e.slots,Gt,1)},al=(e,t,n)=>{const{vnode:s,slots:r}=e;let o=!0,l=L;if(s.shapeFlag&32){const c=t._;c?n&&c===1?o=!1:(X(r,t),!n&&c===1&&delete r._):(o=!t.$stable,vr(t,r)),l=t}else t&&(xr(e,t),l={default:1});if(o)for(const c in r)!br(c)&&!(c in l)&&delete r[c]};function On(e,t,n,s,r=!1){if(P(e)){e.forEach((E,I)=>On(E,t&&(P(t)?t[I]:t),n,s,r));return}if(pt(s)&&!r)return;const o=s.shapeFlag&4?Yn(s.component)||s.component.proxy:s.el,l=r?null:o,{i:c,r:u}=e,a=t&&t.r,_=c.refs===L?c.refs={}:c.refs,y=c.setupState;if(a!=null&&a!==u&&(J(a)?(_[a]=null,R(y,a)&&(y[a]=null)):re(a)&&(a.value=null)),M(u))Re(u,c,12,[l,_]);else{const E=J(u),I=re(u);if(E||I){const q=()=>{if(e.f){const $=E?R(y,u)?y[u]:_[u]:u.value;r?P($)&&Mn($,o):P($)?$.includes(o)||$.push(o):E?(_[u]=[o],R(y,u)&&(y[u]=_[u])):(u.value=[o],e.k&&(_[e.k]=u.value))}else E?(_[u]=l,R(y,u)&&(y[u]=l)):I&&(u.value=l,e.k&&(_[e.k]=l))};l?(q.id=-1,ce(q,n)):q()}}}const ce=Bo;function dl(e){return hl(e)}function hl(e,t){const n=gn();n.__VUE__=!0;const{insert:s,remove:r,patchProp:o,createElement:l,createText:c,createComment:u,setText:a,setElementText:_,parentNode:y,nextSibling:E,setScopeId:I=me,insertStaticContent:q}=e,$=(i,f,d,p=null,h=null,b=null,x=!1,m=null,v=!!f.dynamicChildren)=>{if(i===f)return;i&&!at(i,f)&&(p=It(i),ve(i,h,b,!0),i=null),f.patchFlag===-2&&(v=!1,f.dynamicChildren=null);const{type:g,ref:C,shapeFlag:w}=f;switch(g){case Qt:Z(i,f,d,p);break;case je:Q(i,f,d,p);break;case an:i==null&&G(f,d,p,x);break;case de:Ot(i,f,d,p,h,b,x,m,v);break;default:w&1?Me(i,f,d,p,h,b,x,m,v):w&6?Tt(i,f,d,p,h,b,x,m,v):(w&64||w&128)&&g.process(i,f,d,p,h,b,x,m,v,qe)}C!=null&&h&&On(C,i&&i.ref,b,f||i,!f)},Z=(i,f,d,p)=>{if(i==null)s(f.el=c(f.children),d,p);else{const h=f.el=i.el;f.children!==i.children&&a(h,f.children)}},Q=(i,f,d,p)=>{i==null?s(f.el=u(f.children||""),d,p):f.el=i.el},G=(i,f,d,p)=>{[i.el,i.anchor]=q(i.children,f,d,p,i.el,i.anchor)},ee=({el:i,anchor:f},d,p)=>{let h;for(;i&&i!==f;)h=E(i),s(i,d,p),i=h;s(f,d,p)},F=({el:i,anchor:f})=>{let d;for(;i&&i!==f;)d=E(i),r(i),i=d;r(f)},Me=(i,f,d,p,h,b,x,m,v)=>{x=x||f.type==="svg",i==null?ct(f,d,p,h,b,x,m,v):en(i,f,h,b,x,m,v)},ct=(i,f,d,p,h,b,x,m)=>{let v,g;const{type:C,props:w,shapeFlag:O,transition:T,dirs:A}=i;if(v=i.el=l(i.type,b,w&&w.is,w),O&8?_(v,i.children):O&16&&Ne(i.children,v,null,p,h,b&&C!=="foreignObject",x,m),A&&Le(i,null,p,"created"),Ct(v,i,i.scopeId,x,p),w){for(const B in w)B!=="value"&&!jt(B)&&o(v,B,null,w[B],b,i.children,p,h,Oe);"value"in w&&o(v,"value",null,w.value),(g=w.onVnodeBeforeMount)&&ye(g,p,i)}A&&Le(i,null,p,"beforeMount");const H=(!h||h&&!h.pendingBranch)&&T&&!T.persisted;H&&T.beforeEnter(v),s(v,f,d),((g=w&&w.onVnodeMounted)||H||A)&&ce(()=>{g&&ye(g,p,i),H&&T.enter(v),A&&Le(i,null,p,"mounted")},h)},Ct=(i,f,d,p,h)=>{if(d&&I(i,d),p)for(let b=0;b{for(let g=v;g{const m=f.el=i.el;let{patchFlag:v,dynamicChildren:g,dirs:C}=f;v|=i.patchFlag&16;const w=i.props||L,O=f.props||L;let T;d&&Ue(d,!1),(T=O.onVnodeBeforeUpdate)&&ye(T,d,f,i),C&&Le(f,i,d,"beforeUpdate"),d&&Ue(d,!0);const A=h&&f.type!=="foreignObject";if(g?Be(i.dynamicChildren,g,m,d,p,A,b):x||D(i,f,m,null,d,p,A,b,!1),v>0){if(v&16)ft(m,f,w,O,d,p,h);else if(v&2&&w.class!==O.class&&o(m,"class",null,O.class,h),v&4&&o(m,"style",w.style,O.style,h),v&8){const H=f.dynamicProps;for(let B=0;B{T&&ye(T,d,f,i),C&&Le(f,i,d,"updated")},p)},Be=(i,f,d,p,h,b,x)=>{for(let m=0;m{if(d!==p){if(d!==L)for(const m in d)!jt(m)&&!(m in p)&&o(i,m,d[m],null,x,f.children,h,b,Oe);for(const m in p){if(jt(m))continue;const v=p[m],g=d[m];v!==g&&m!=="value"&&o(i,m,g,v,x,f.children,h,b,Oe)}"value"in p&&o(i,"value",d.value,p.value)}},Ot=(i,f,d,p,h,b,x,m,v)=>{const g=f.el=i?i.el:c(""),C=f.anchor=i?i.anchor:c("");let{patchFlag:w,dynamicChildren:O,slotScopeIds:T}=f;T&&(m=m?m.concat(T):T),i==null?(s(g,d,p),s(C,d,p),Ne(f.children,d,C,h,b,x,m,v)):w>0&&w&64&&O&&i.dynamicChildren?(Be(i.dynamicChildren,O,d,h,b,x,m),(f.key!=null||h&&f===h.subTree)&&yr(i,f,!0)):D(i,f,d,C,h,b,x,m,v)},Tt=(i,f,d,p,h,b,x,m,v)=>{f.slotScopeIds=m,i==null?f.shapeFlag&512?h.ctx.activate(f,d,p,x,v):tn(f,d,p,h,b,x,v):Zn(i,f,v)},tn=(i,f,d,p,h,b,x)=>{const m=i.component=wl(i,p,h);if(cr(i)&&(m.ctx.renderer=qe),El(m),m.asyncDep){if(h&&h.registerDep(m,oe),!i.el){const v=m.subTree=S(je);Q(null,v,f,d)}return}oe(m,i,f,d,h,b,x)},Zn=(i,f,d)=>{const p=f.component=i.component;if(So(i,f,d))if(p.asyncDep&&!p.asyncResolved){z(p,f,d);return}else p.next=f,Io(p.update),p.update();else f.el=i.el,p.vnode=f},oe=(i,f,d,p,h,b,x)=>{const m=()=>{if(i.isMounted){let{next:C,bu:w,u:O,parent:T,vnode:A}=i,H=C,B;Ue(i,!1),C?(C.el=A.el,z(i,C,x)):C=A,w&&on(w),(B=C.props&&C.props.onVnodeBeforeUpdate)&&ye(B,T,C,A),Ue(i,!0);const Y=cn(i),he=i.subTree;i.subTree=Y,$(he,Y,y(he.el),It(he),i,h,b),C.el=Y.el,H===null&&jo(i,Y.el),O&&ce(O,h),(B=C.props&&C.props.onVnodeUpdated)&&ce(()=>ye(B,T,C,A),h)}else{let C;const{el:w,props:O}=f,{bm:T,m:A,parent:H}=i,B=pt(f);if(Ue(i,!1),T&&on(T),!B&&(C=O&&O.onVnodeBeforeMount)&&ye(C,H,f),Ue(i,!0),w&&sn){const Y=()=>{i.subTree=cn(i),sn(w,i.subTree,i,h,null)};B?f.type.__asyncLoader().then(()=>!i.isUnmounted&&Y()):Y()}else{const Y=i.subTree=cn(i);$(null,Y,d,p,i,h,b),f.el=Y.el}if(A&&ce(A,h),!B&&(C=O&&O.onVnodeMounted)){const Y=f;ce(()=>ye(C,H,Y),h)}(f.shapeFlag&256||H&&pt(H.vnode)&&H.vnode.shapeFlag&256)&&i.a&&ce(i.a,h),i.isMounted=!0,f=d=p=null}},v=i.effect=new Rn(m,()=>Un(g),i.scope),g=i.update=()=>v.run();g.id=i.uid,Ue(i,!0),g()},z=(i,f,d)=>{f.component=i;const p=i.vnode.props;i.vnode=f,i.next=null,cl(i,f.props,p,d),al(i,f.children,d),lt(),fs(),it()},D=(i,f,d,p,h,b,x,m,v=!1)=>{const g=i&&i.children,C=i?i.shapeFlag:0,w=f.children,{patchFlag:O,shapeFlag:T}=f;if(O>0){if(O&128){Pt(g,w,d,p,h,b,x,m,v);return}else if(O&256){De(g,w,d,p,h,b,x,m,v);return}}T&8?(C&16&&Oe(g,h,b),w!==g&&_(d,w)):C&16?T&16?Pt(g,w,d,p,h,b,x,m,v):Oe(g,h,b,!0):(C&8&&_(d,""),T&16&&Ne(w,d,p,h,b,x,m,v))},De=(i,f,d,p,h,b,x,m,v)=>{i=i||Ve,f=f||Ve;const g=i.length,C=f.length,w=Math.min(g,C);let O;for(O=0;OC?Oe(i,h,b,!0,!1,w):Ne(f,d,p,h,b,x,m,v,w)},Pt=(i,f,d,p,h,b,x,m,v)=>{let g=0;const C=f.length;let w=i.length-1,O=C-1;for(;g<=w&&g<=O;){const T=i[g],A=f[g]=v?Ae(f[g]):Ee(f[g]);if(at(T,A))$(T,A,d,null,h,b,x,m,v);else break;g++}for(;g<=w&&g<=O;){const T=i[w],A=f[O]=v?Ae(f[O]):Ee(f[O]);if(at(T,A))$(T,A,d,null,h,b,x,m,v);else break;w--,O--}if(g>w){if(g<=O){const T=O+1,A=TO)for(;g<=w;)ve(i[g],h,b,!0),g++;else{const T=g,A=g,H=new Map;for(g=A;g<=O;g++){const ae=f[g]=v?Ae(f[g]):Ee(f[g]);ae.key!=null&&H.set(ae.key,g)}let B,Y=0;const he=O-A+1;let Ye=!1,Qn=0;const ut=new Array(he);for(g=0;g=he){ve(ae,h,b,!0);continue}let xe;if(ae.key!=null)xe=H.get(ae.key);else for(B=A;B<=O;B++)if(ut[B-A]===0&&at(ae,f[B])){xe=B;break}xe===void 0?ve(ae,h,b,!0):(ut[xe-A]=g+1,xe>=Qn?Qn=xe:Ye=!0,$(ae,f[xe],d,null,h,b,x,m,v),Y++)}const Gn=Ye?pl(ut):Ve;for(B=Gn.length-1,g=he-1;g>=0;g--){const ae=A+g,xe=f[ae],es=ae+1{const{el:b,type:x,transition:m,children:v,shapeFlag:g}=i;if(g&6){He(i.component.subTree,f,d,p);return}if(g&128){i.suspense.move(f,d,p);return}if(g&64){x.move(i,f,d,qe);return}if(x===de){s(b,f,d);for(let w=0;wm.enter(b),h);else{const{leave:w,delayLeave:O,afterLeave:T}=m,A=()=>s(b,f,d),H=()=>{w(b,()=>{A(),T&&T()})};O?O(b,A,H):H()}else s(b,f,d)},ve=(i,f,d,p=!1,h=!1)=>{const{type:b,props:x,ref:m,children:v,dynamicChildren:g,shapeFlag:C,patchFlag:w,dirs:O}=i;if(m!=null&&On(m,null,d,i,!0),C&256){f.ctx.deactivate(i);return}const T=C&1&&O,A=!pt(i);let H;if(A&&(H=x&&x.onVnodeBeforeUnmount)&&ye(H,f,i),C&6)Mr(i.component,d,p);else{if(C&128){i.suspense.unmount(d,p);return}T&&Le(i,null,f,"beforeUnmount"),C&64?i.type.remove(i,f,d,h,qe,p):g&&(b!==de||w>0&&w&64)?Oe(g,f,d,!1,!0):(b===de&&w&384||!h&&C&16)&&Oe(v,f,d),p&&Vn(i)}(A&&(H=x&&x.onVnodeUnmounted)||T)&&ce(()=>{H&&ye(H,f,i),T&&Le(i,null,f,"unmounted")},d)},Vn=i=>{const{type:f,el:d,anchor:p,transition:h}=i;if(f===de){Ir(d,p);return}if(f===an){F(i);return}const b=()=>{r(d),h&&!h.persisted&&h.afterLeave&&h.afterLeave()};if(i.shapeFlag&1&&h&&!h.persisted){const{leave:x,delayLeave:m}=h,v=()=>x(d,b);m?m(i.el,b,v):v()}else b()},Ir=(i,f)=>{let d;for(;i!==f;)d=E(i),r(i),i=d;r(f)},Mr=(i,f,d)=>{const{bum:p,scope:h,update:b,subTree:x,um:m}=i;p&&on(p),h.stop(),b&&(b.active=!1,ve(x,i,f,d)),m&&ce(m,f),ce(()=>{i.isUnmounted=!0},f),f&&f.pendingBranch&&!f.isUnmounted&&i.asyncDep&&!i.asyncResolved&&i.suspenseId===f.pendingId&&(f.deps--,f.deps===0&&f.resolve())},Oe=(i,f,d,p=!1,h=!1,b=0)=>{for(let x=b;xi.shapeFlag&6?It(i.component.subTree):i.shapeFlag&128?i.suspense.next():E(i.anchor||i.el),Xn=(i,f,d)=>{i==null?f._vnode&&ve(f._vnode,null,null,!0):$(f._vnode||null,i,f,null,null,null,d),fs(),nr(),f._vnode=i},qe={p:$,um:ve,m:He,r:Vn,mt:tn,mc:Ne,pc:D,pbc:Be,n:It,o:e};let nn,sn;return t&&([nn,sn]=t(qe)),{render:Xn,hydrate:nn,createApp:ol(Xn,nn)}}function Ue({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function yr(e,t,n=!1){const s=e.children,r=t.children;if(P(s)&&P(r))for(let o=0;o>1,e[n[c]]0&&(t[s]=n[o-1]),n[o]=s)}}for(o=n.length,l=n[o-1];o-- >0;)n[o]=l,l=t[l];return n}const gl=e=>e.__isTeleport,de=Symbol.for("v-fgt"),Qt=Symbol.for("v-txt"),je=Symbol.for("v-cmt"),an=Symbol.for("v-stc"),_t=[];let _e=null;function V(e=!1){_t.push(_e=e?null:[])}function _l(){_t.pop(),_e=_t[_t.length-1]||null}let wt=1;function vs(e){wt+=e}function wr(e){return e.dynamicChildren=wt>0?_e||Ve:null,_l(),wt>0&&_e&&_e.push(e),e}function ie(e,t,n,s,r,o){return wr(K(e,t,n,s,r,o,!0))}function zn(e,t,n,s,r){return wr(S(e,t,n,s,r,!0))}function Er(e){return e?e.__v_isVNode===!0:!1}function at(e,t){return e.type===t.type&&e.key===t.key}const Gt="__vInternal",Cr=({key:e})=>e??null,Bt=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?J(e)||re(e)||M(e)?{i:fe,r:e,k:t,f:!!n}:e:null);function K(e,t=null,n=null,s=0,r=null,o=e===de?0:1,l=!1,c=!1){const u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Cr(t),ref:t&&Bt(t),scopeId:or,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:s,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:fe};return c?(kn(u,n),o&128&&e.normalize(u)):n&&(u.shapeFlag|=J(n)?8:16),wt>0&&!l&&_e&&(u.patchFlag>0||o&6)&&u.patchFlag!==32&&_e.push(u),u}const S=ml;function ml(e,t=null,n=null,s=0,r=null,o=!1){if((!e||e===Vo)&&(e=je),Er(e)){const c=nt(e,t,!0);return n&&kn(c,n),wt>0&&!o&&_e&&(c.shapeFlag&6?_e[_e.indexOf(e)]=c:_e.push(c)),c.patchFlag|=-2,c}if(Pl(e)&&(e=e.__vccOpts),t){t=bl(t);let{class:c,style:u}=t;c&&!J(c)&&(t.class=ot(c)),W(u)&&(Zs(u)&&!P(u)&&(u=X({},u)),t.style=qt(u))}const l=J(e)?1:No(e)?128:gl(e)?64:W(e)?4:M(e)?2:0;return K(e,t,n,s,r,l,o,!0)}function bl(e){return e?Zs(e)||Gt in e?X({},e):e:null}function nt(e,t,n=!1){const{props:s,ref:r,patchFlag:o,children:l}=e,c=t?vl(s||{},t):s;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&Cr(c),ref:t&&t.ref?n&&r?P(r)?r.concat(Bt(t)):[r,Bt(t)]:Bt(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==de?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&nt(e.ssContent),ssFallback:e.ssFallback&&nt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function N(e=" ",t=0){return S(Qt,null,e,t)}function mt(e="",t=!1){return t?(V(),zn(je,null,e)):S(je,null,e)}function Ee(e){return e==null||typeof e=="boolean"?S(je):P(e)?S(de,null,e.slice()):typeof e=="object"?Ae(e):S(Qt,null,String(e))}function Ae(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:nt(e)}function kn(e,t){let n=0;const{shapeFlag:s}=e;if(t==null)t=null;else if(P(t))n=16;else if(typeof t=="object")if(s&65){const r=t.default;r&&(r._c&&(r._d=!1),kn(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!(Gt in t)?t._ctx=fe:r===3&&fe&&(fe.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else M(t)?(t={default:t,_ctx:fe},n=32):(t=String(t),s&64?(n=16,t=[N(t)]):n=8);e.children=t,e.shapeFlag|=n}function vl(...e){const t={};for(let n=0;nse=e),qn=e=>{Je.length>1?Je.forEach(t=>t(e)):Je[0](e)};const st=e=>{qn(e),e.scope.on()},ke=()=>{se&&se.scope.off(),qn(null)};function Or(e){return e.vnode.shapeFlag&4}let Et=!1;function El(e,t=!1){Et=t;const{props:n,children:s}=e.vnode,r=Or(e);il(e,n,r,t),ul(e,s);const o=r?Cl(e,t):void 0;return Et=!1,o}function Cl(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Vs(new Proxy(e.ctx,Qo));const{setup:s}=n;if(s){const r=e.setupContext=s.length>1?Tl(e):null;st(e),lt();const o=Re(s,e,0,[e.props,r]);if(it(),ke(),$s(o)){if(o.then(ke,ke),t)return o.then(l=>{ys(e,l,t)}).catch(l=>{Jt(l,e,0)});e.asyncDep=o}else ys(e,o,t)}else Tr(e,t)}function ys(e,t,n){M(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:W(t)&&(e.setupState=Gs(t)),Tr(e,n)}let ws;function Tr(e,t,n){const s=e.type;if(!e.render){if(!t&&ws&&!s.render){const r=s.template||Kn(e).template;if(r){const{isCustomElement:o,compilerOptions:l}=e.appContext.config,{delimiters:c,compilerOptions:u}=s,a=X(X({isCustomElement:o,delimiters:c},l),u);s.render=ws(r,a)}}e.render=s.render||me}st(e),lt(),Go(e),it(),ke()}function Ol(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return ue(e,"get","$attrs"),t[n]}}))}function Tl(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Ol(e)},slots:e.slots,emit:e.emit,expose:t}}function Yn(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Gs(Vs(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in gt)return gt[n](e)},has(t,n){return n in t||n in gt}}))}function Pl(e){return M(e)&&"__vccOpts"in e}const Pr=(e,t)=>Co(e,t,Et),Il=Symbol.for("v-scx"),Ml=()=>Nt(Il),Fl="3.3.4",Al="http://www.w3.org/2000/svg",We=typeof document<"u"?document:null,Es=We&&We.createElement("template"),$l={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const r=t?We.createElementNS(Al,e):We.createElement(e,n?{is:n}:void 0);return e==="select"&&s&&s.multiple!=null&&r.setAttribute("multiple",s.multiple),r},createText:e=>We.createTextNode(e),createComment:e=>We.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>We.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,r,o){const l=n?n.previousSibling:t.lastChild;if(r&&(r===o||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===o||!(r=r.nextSibling)););else{Es.innerHTML=s?`${e}`:e;const c=Es.content;if(s){const u=c.firstChild;for(;u.firstChild;)c.appendChild(u.firstChild);c.removeChild(u)}t.insertBefore(c,n)}return[l?l.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function Rl(e,t,n){const s=e._vtc;s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function Sl(e,t,n){const s=e.style,r=J(n);if(n&&!r){if(t&&!J(t))for(const o in t)n[o]==null&&Tn(s,o,"");for(const o in n)Tn(s,o,n[o])}else{const o=s.display;r?t!==n&&(s.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(s.display=o)}}const Cs=/\s*!important$/;function Tn(e,t,n){if(P(n))n.forEach(s=>Tn(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=jl(e,t);Cs.test(n)?e.setProperty(rt(s),n.replace(Cs,""),"important"):e[s]=n}}const Os=["Webkit","Moz","ms"],dn={};function jl(e,t){const n=dn[t];if(n)return n;let s=et(t);if(s!=="filter"&&s in e)return dn[t]=s;s=js(s);for(let r=0;rhn||(Kl.then(()=>hn=0),hn=Date.now());function zl(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;be(kl(s,n.value),t,5,[s])};return n.value=e,n.attached=Wl(),n}function kl(e,t){if(P(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>r=>!r._stopped&&s&&s(r))}else return t}const Is=/^on[a-z]/,ql=(e,t,n,s,r=!1,o,l,c,u)=>{t==="class"?Rl(e,s,r):t==="style"?Sl(e,n,s):Wt(t)?In(t)||Ll(e,t,n,s,l):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Yl(e,t,s,r))?Bl(e,t,s,o,l,c,u):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),Nl(e,t,s,r))};function Yl(e,t,n,s){return s?!!(t==="innerHTML"||t==="textContent"||t in e&&Is.test(t)&&M(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Is.test(t)&&J(n)?!1:t in e}const Jl=X({patchProp:ql},$l);let Ms;function Zl(){return Ms||(Ms=dl(Jl))}const Vl=(...e)=>{const t=Zl().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=Xl(s);if(!r)return;const o=t._component;!M(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.innerHTML="";const l=n(r,!1,r instanceof SVGElement);return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),l},t};function Xl(e){return J(e)?document.querySelector(e):e}const Jn=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Ql={},Gl={xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},ei=K("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18"},null,-1),ti=[ei];function ni(e,t){return V(),ie("svg",Gl,ti)}const si=Jn(Ql,[["render",ni]]),ri={},oi={xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},li=K("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3"},null,-1),ii=[li];function ci(e,t){return V(),ie("svg",oi,ii)}const fi=Jn(ri,[["render",ci]]),ui={class:"inline-block text-sm bg-gray-200 rounded-full overflow-hidden relative"},ai=Vt({__name:"Progress",props:{value:{},max:{}},setup(e){return(t,n)=>(V(),ie("div",ui,[K("div",{class:ot(["px-2 text-sm transition-[width] duration-500 whitespace-nowrap",{"bg-gray-400/50":t.value/t.max<.8,"bg-orange-300":t.value/t.max>=.8&&t.value/t.max<.9,"bg-red-300":t.value/t.max>=.9}]),style:qt({width:`${t.value/t.max*100}%`})},[dr(t.$slots,"default")],6)]))}}),di={},hi={class:"inline-block bg-gray-200 px-2 rounded-full text-sm"};function pi(e,t){return V(),ie("div",hi,[dr(e.$slots,"default")])}const gi=Jn(di,[["render",pi]]),_i=Vt({__name:"StatusIndicator",props:{status:{type:Boolean}},setup(e){return(t,n)=>(V(),ie("div",{class:ot(["rounded-full inline-block",{"bg-green-400":t.status,"bg-red-500":!t.status}])},null,2))}});function we(e,t=2){if(e===0)return"0 B";const n=1024,s=t<0?0:t,r=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],o=Math.floor(Math.log(e)/Math.log(n));return`${Number.parseFloat((e/n**o).toFixed(s))} ${r[o]}`}function mi(e){const t=new Date(e*1e3),n=t.getFullYear(),s=(t.getMonth()+1).toString().padStart(2,"0"),r=t.getDate().toString().padStart(2,"0"),o=t.getHours().toString().padStart(2,"0"),l=t.getMinutes().toString().padStart(2,"0"),c=t.getSeconds().toString().padStart(2,"0");return`${n}/${s}/${r} ${o}:${l}:${c}`}function pn(e){return e.online4||e.online6}function bi(e){return/[\uD800-\uDBFF][\uDC00-\uDFFF]/g.test(e)}const vi={class:"rounded-xl px-4 py-3 transition-all relative bg-gray-100 border border-transparent hover:border-gray-400 hover:shadow-md hover:bg-white duration-300"},xi={class:"absolute right-4 top-4 group flex flex-col items-end"},yi={class:"hidden group-hover:block p-2 rounded-xl border text-sm bg-white z-[9999] mt-1 border-gray-400"},wi={class:"flex gap-2"},Ei={class:"flex items-center gap-1"},Ci={class:"flex items-center gap-1"},Oi={key:0},Ti=K("br",null,null,-1),Pi={class:"text-lg flex items-center gap-2"},Ii={key:0},Mi=["src","alt"],Fi=["src","alt"],Ai={class:"flex items-center gap-2"},$i={class:"flex items-center gap-2"},Ri={class:"flex items-center gap-2"},Si={class:"flex items-center gap-2"},ji={class:"flex items-center gap-2"},Ni={class:"flex items-center gap-2"},Bi={class:"flex gap-1 flex-wrap mt-1"},Di=Vt({__name:"ServerItem",props:{server:{}},setup(e){const t=e,n=Pr(()=>{if(!t.server.labels)return{};const s=t.server.labels.split(";"),r={};return s.forEach(o=>{if(o==="")return;const[l,c]=o.split("=");r[l]=c}),r});return(s,r)=>{const o=_i,l=gi,c=ai,u=fi,a=si;return V(),ie("div",vi,[K("div",xi,[S(o,{status:U(pn)(s.server),class:"w-3 h-3"},null,8,["status"]),K("div",yi,[K("div",wi,[K("div",Ei,[N(" IPv4 "),S(o,{status:s.server.online4,class:"w-2 h-2"},null,8,["status"])]),K("div",Ci,[N(" IPv6 "),S(o,{status:s.server.online6,class:"w-2 h-2"},null,8,["status"])])]),s.server.latest_ts?(V(),ie("div",Oi,[N(" 最后上报时间"),Ti,N(" "+k(U(mi)(s.server.latest_ts)),1)])):mt("",!0)])]),K("div",Pi,[U(bi)(s.server.location)?(V(),ie("span",Ii,k(s.server.location),1)):(V(),ie("img",{key:1,src:`/image/flags/${s.server.location}.svg`,alt:`${s.server.location} flag`,class:"h-4 inline-block rounded-sm"},null,8,Mi)),U(n).os?(V(),ie("img",{key:2,src:`/image/os/${U(n).os}.svg`,alt:`${U(n).os} os`,class:"h-4 inline-block rounded-sm"},null,8,Fi)):mt("",!0),N(" "+k(s.server.alias||s.server.name),1)]),K("div",null,[N(" 运行时间 "),K("span",{class:ot({"text-red-500":!U(pn)(s.server)})},k(U(pn)(s.server)?s.server.uptime:"离线"),3)]),K("div",Ai,[N(" 负载 "),S(l,null,{default:te(()=>[N(k(s.server.load_1),1)]),_:1}),S(l,null,{default:te(()=>[N(k(s.server.load_5),1)]),_:1}),S(l,null,{default:te(()=>[N(k(s.server.load_15),1)]),_:1})]),K("div",$i,[N(" CPU "),S(c,{value:s.server.cpu,max:100,text:`${s.server.cpu}%`,class:"flex-1"},{default:te(()=>[N(k(s.server.cpu)+"% ",1)]),_:1},8,["value","text"])]),K("div",Ri,[N(" 内存 "),S(c,{value:s.server.memory_used,max:s.server.memory_total,class:"flex-1"},{default:te(()=>[N(k(U(we)(s.server.memory_used*1024))+" / "+k(U(we)(s.server.memory_total*1024)),1)]),_:1},8,["value","max"])]),K("div",Si,[N(" 硬盘 "),S(c,{value:s.server.hdd_used,max:s.server.hdd_total,class:"flex-1"},{default:te(()=>[N(k(U(we)(s.server.hdd_used*1024*1024))+" / "+k(U(we)(s.server.hdd_total*1024*1024)),1)]),_:1},8,["value","max"])]),K("div",ji,[N(" 网络 "),S(l,{class:"flex items-center"},{default:te(()=>[S(u,{class:"w-4 h-4"}),N(k(U(we)(s.server.network_rx,1))+"/s ",1)]),_:1}),S(l,{class:"flex items-center"},{default:te(()=>[S(a,{class:"w-4 h-4"}),N(k(U(we)(s.server.network_tx,1))+"/s ",1)]),_:1})]),K("div",Ni,[N(" 流量 "),S(l,{class:"flex items-center"},{default:te(()=>[S(u,{class:"w-4 h-4"}),N(k(U(we)(s.server.network_in,1)),1)]),_:1}),S(l,{class:"flex items-center"},{default:te(()=>[S(a,{class:"w-4 h-4"}),N(k(U(we)(s.server.network_out,1)),1)]),_:1})]),K("div",null,[N(" SWAP "),S(l,null,{default:te(()=>[N(k(U(we)(s.server.swap_used*1024))+" / "+k(U(we)(s.server.swap_total*1024)),1)]),_:1})]),K("div",Bi,[S(l,null,{default:te(()=>[N(" TCP "+k(s.server.tcp_count),1)]),_:1}),S(l,null,{default:te(()=>[N(" UDP "+k(s.server.udp_count),1)]),_:1}),S(l,null,{default:te(()=>[N(" 进程 "+k(s.server.process_count),1)]),_:1}),S(l,null,{default:te(()=>[N(" 线程 "+k(s.server.thread_count),1)]),_:1})])])}}}),Hi={key:0,class:"w-fit mx-auto my-2"},Li={key:1,class:"w-fit mx-auto my-2"},Ui={key:2,class:"flex flex-wrap gap-x-4 gap-y-3"},Ki=K("div",{class:"h-16"},null,-1),Fs="/json/stats.json",Wi=Vt({__name:"App",setup(e){const t=ln(),n=ln(!0),s=ln(!1);ur(()=>{fetch(Fs).then(o=>o.json()).then(o=>{t.value=o,setInterval(()=>{r()},1e3)}).catch(()=>{s.value=!0}).finally(()=>{n.value=!1})});function r(){fetch(Fs).then(o=>o.json()).then(o=>{t.value=o,s.value=!1}).catch(()=>{s.value=!0})}return(o,l)=>{const c=Di;return V(),ie(de,null,[U(n)?(V(),ie("div",Hi," 加载中 ")):mt("",!0),U(s)?(V(),ie("div",Li," 数据加载失败,请尝试刷新页面或检查 ServerStatus 服务端状态 ")):mt("",!0),U(t)?(V(),ie("div",Ui,[(V(!0),ie(de,null,Xo(U(t).servers,u=>(V(),zn(c,{key:u.name,server:u,class:"flex-1 min-w-[300px]"},null,8,["server"]))),128))])):mt("",!0),Ki],64)}}});const zi=Vl(Wi);zi.mount("#app"); diff --git a/web/index3.html b/web/index3.html index 2f37a01b..bcd7ccdc 100644 --- a/web/index3.html +++ b/web/index3.html @@ -6,7 +6,7 @@ ServerStatus - + From 4a9f5adb6bd3cadd87372dcabc48ed2bd1300fb4 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 17 Oct 2023 09:49:44 +0800 Subject: [PATCH 087/144] Update index3.html cppla/Serverstatus version modify --- web/index3.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/index3.html b/web/index3.html index bcd7ccdc..ac2a1902 100644 --- a/web/index3.html +++ b/web/index3.html @@ -17,8 +17,8 @@

- Powered by ServerStatus-Rust. + Powered by ServerStatus中文版. Theme Light by OriLight
From 5ebf076330ce911f32cb932e463544534e58155c Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Mon, 1 Jan 2024 00:00:00 +0000 Subject: [PATCH 088/144] Update ExprTk to 0.0.3 --- server/src/exprtk.hpp | 13501 +++++++++++++++++++++++++++------------- 1 file changed, 9292 insertions(+), 4209 deletions(-) diff --git a/server/src/exprtk.hpp b/server/src/exprtk.hpp index b4530ba0..da493c59 100644 --- a/server/src/exprtk.hpp +++ b/server/src/exprtk.hpp @@ -2,7 +2,7 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2023) * + * Author: Arash Partow (1999-2024) * * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -10,6 +10,7 @@ * permitted under the guidelines and in accordance with the most * * current version of the MIT License. * * https://www.opensource.org/licenses/MIT * + * SPDX-License-Identifier: MIT * * * * Example expressions: * * (00) (y + x / y) * (x - y / x) * @@ -17,12 +18,12 @@ * (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) * + * (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) * + * (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)] * * * @@ -42,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -67,20 +67,6 @@ namespace exprtk #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 - #if __cplusplus >= 201103L #define exprtk_override override #define exprtk_final final @@ -91,6 +77,18 @@ namespace exprtk #define exprtk_delete #endif + #if __cplusplus >= 201603L + #define exprtk_fallthrough [[fallthrough]]; + #elif __cplusplus >= 201103L + #define exprtk_fallthrough [[gnu::fallthrough]]; + #else + #ifndef _MSC_VER + #define exprtk_fallthrough __attribute__ ((fallthrough)); + #else + #define exprtk_fallthrough + #endif + #endif + namespace details { typedef char char_t; @@ -218,15 +216,15 @@ namespace exprtk { const std::size_t length = std::min(s1.size(),s2.size()); - for (std::size_t i = 0; i < length; ++i) + for (std::size_t i = 0; i < length; ++i) { const char_t c1 = static_cast(std::tolower(s1[i])); const char_t c2 = static_cast(std::tolower(s2[i])); - if (c1 > c2) - return false; - else if (c1 < c2) + if (c1 < c2) return true; + else if (c2 < c1) + return false; } return s1.size() < s2.size(); @@ -364,9 +362,9 @@ namespace exprtk } else if (parse_hex(itr1, end, *itr2)) { - itr1+= 4; - itr2+= 1; - removal_count +=4; + 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; } @@ -381,6 +379,7 @@ namespace exprtk (*itr2++) = (*itr1++); ++removal_count; } + continue; } else @@ -432,85 +431,85 @@ namespace exprtk }; 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", "&", "|" - }; + { + "assert", "break", "case", "continue", "const", "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", "&", "|" - }; + { + "abs", "acos", "acosh", "and", "asin", "asinh", "assert", + "atan", "atanh", "atan2", "avg", "break", "case", "ceil", + "clamp", "continue", "const", "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" - }; + { + "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", "&", "|" - }; + { + "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" - }; + { + "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); @@ -646,7 +645,7 @@ namespace exprtk } } else if (data_end == d_itr) - return true; + break; if ((data_end == d_itr) || (null_itr == nd_itr)) return false; @@ -661,23 +660,27 @@ namespace exprtk inline bool wc_match(const std::string& wild_card, const std::string& str) { - return match_impl( + return match_impl + ( wild_card.data(), wild_card.data() + wild_card.size(), str.data(), str.data() + str.size(), - '*', '?'); + '*', '?' + ); } inline bool wc_imatch(const std::string& wild_card, const std::string& str) { - return match_impl( + return match_impl + ( wild_card.data(), wild_card.data() + wild_card.size(), str.data(), str.data() + str.size(), - '*', '?'); + '*', '?' + ); } inline bool sequence_match(const std::string& pattern, @@ -750,13 +753,55 @@ namespace exprtk ); } - 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 - }; + template + struct set_zero_value_impl + { + static inline void process(T* base_ptr, const std::size_t size) + { + const T zero = T(0); + for (std::size_t i = 0; i < size; ++i) + { + base_ptr[i] = zero; + } + } + }; + + #define pod_set_zero_value(T) \ + template <> \ + struct set_zero_value_impl \ + { \ + static inline void process(T* base_ptr, const std::size_t size) \ + { std::memset(base_ptr, 0x00, size * sizeof(T)); } \ + }; \ + + pod_set_zero_value(float ) + pod_set_zero_value(double ) + pod_set_zero_value(long double) + + #ifdef pod_set_zero_value + #undef pod_set_zero_value + #endif + + template + inline void set_zero_value(T* data, const std::size_t size) + { + set_zero_value_impl::process(data,size); + } + + template + inline void set_zero_value(std::vector& v) + { + set_zero_value(v.data(),v.size()); + } + + 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); @@ -789,17 +834,17 @@ namespace exprtk number_type() {} }; - #define exprtk_register_real_type_tag(T) \ - template <> struct number_type \ - { typedef real_type_tag type; number_type() {} }; \ + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ - template <> struct number_type \ - { typedef int_type_tag type; number_type() {} }; \ + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { typedef int_type_tag type; number_type() {} }; \ + exprtk_register_real_type_tag(float ) exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) - exprtk_register_real_type_tag(float ) exprtk_register_int_type_tag(short ) exprtk_register_int_type_tag(int ) @@ -848,6 +893,12 @@ namespace exprtk return static_cast<_int64_t>(v); } + template + inline _uint64_t to_uint64_impl(const T v, real_type_tag) + { + return static_cast<_uint64_t>(v); + } + template inline bool is_true_impl(const T v) { @@ -982,8 +1033,8 @@ namespace exprtk else return (T(-0.5) * v + T(1)) * v; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -993,8 +1044,8 @@ namespace exprtk { return std::log(T(1) + v); } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -1193,9 +1244,9 @@ namespace exprtk #define exprtk_define_erf(TT, impl) \ inline TT erf_impl(const TT v) { return impl(v); } \ - exprtk_define_erf( float,::erff) - exprtk_define_erf( double,::erf ) - exprtk_define_erf(long double,::erfl) + exprtk_define_erf(float , ::erff) + exprtk_define_erf(double , ::erf ) + exprtk_define_erf(long double, ::erfl) #undef exprtk_define_erf #endif @@ -1204,13 +1255,14 @@ namespace exprtk { #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) - }; + 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())); @@ -1262,10 +1314,7 @@ namespace exprtk template inline T ncdf_impl(const T v, real_type_tag) { - const T cnd = T(0.5) * (T(1) + - erf_impl(abs_impl(v,real_type_tag()) / - T(numeric::constant::sqrt2),real_type_tag())); - return (v < T(0)) ? (T(1) - cnd) : cnd; + return T(0.5) * erfc_impl(-(v / T(numeric::constant::sqrt2)),real_type_tag()); } template @@ -1289,12 +1338,47 @@ namespace exprtk return sinc_impl(static_cast(v),real_type_tag()); } + #if __cplusplus >= 201103L + template + inline T acosh_impl(const T v, real_type_tag) + { + return std::acosh(v); + } + + template + inline T asinh_impl(const T v, real_type_tag) + { + return std::asinh(v); + } + + template + inline T atanh_impl(const T v, real_type_tag) + { + return std::atanh(v); + } + #else + template + inline T acosh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) - T(1))); + } + + template + inline T asinh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) + T(1))); + } + + template + inline T atanh_impl(const T v, real_type_tag) + { + return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); + } + #endif + template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } - template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } - template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } - template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } @@ -1390,6 +1474,13 @@ namespace exprtk return to_int64_impl(v, num_type); } + template + inline _uint64_t to_uint64(const T v) + { + const typename details::number_type::type num_type; + return to_uint64_impl(v, num_type); + } + template inline bool is_nan(const T v) { @@ -1629,38 +1720,38 @@ namespace exprtk { 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 + 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(sizeof(fract10) / sizeof(double)); @@ -1710,7 +1801,6 @@ namespace exprtk if (length <= 4) { - exprtk_disable_fallthrough_begin switch (length) { #ifdef exprtk_use_lut @@ -1723,17 +1813,19 @@ namespace exprtk return_result = false; \ break; \ } \ + exprtk_fallthrough \ #else - #define exprtk_process_digit \ - if ((digit = (*itr++ - zero)) < 10) \ - result = result * T(10) + digit; \ - else \ - { \ - return_result = false; \ - break; \ - } \ + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ + exprtk_fallthrough \ #endif @@ -1748,7 +1840,6 @@ namespace exprtk #undef exprtk_process_digit } - exprtk_disable_fallthrough_end } else return_result = false; @@ -2067,14 +2158,74 @@ namespace exprtk virtual void handle_runtime_violation(const violation_context&) { - throw std::runtime_error("ExprTk Loop run-time violation."); + throw std::runtime_error("ExprTk Loop runtime violation."); } - virtual ~loop_runtime_check() {} + virtual ~loop_runtime_check() + {} }; typedef loop_runtime_check* loop_runtime_check_ptr; + struct vector_access_runtime_check + { + struct violation_context + { + void* base_ptr; + void* end_ptr; + void* access_ptr; + std::size_t type_size; + }; + + virtual ~vector_access_runtime_check() + {} + + virtual bool handle_runtime_violation(violation_context& /*context*/) + { + throw std::runtime_error("ExprTk runtime vector access violation."); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) + return false; + #endif + } + }; + + typedef vector_access_runtime_check* vector_access_runtime_check_ptr; + + struct assert_check + { + struct assert_context + { + std::string condition; + std::string message; + std::string id; + std::size_t offet; + }; + + virtual ~assert_check() + {} + + virtual void handle_assert(const assert_context& /*context*/) + { + } + }; + + typedef assert_check* assert_check_ptr; + + struct compilation_check + { + struct compilation_context + { + std::string error_message; + }; + + virtual bool continue_compilation(compilation_context& /*context*/) = 0; + + virtual ~compilation_check() + {} + }; + + typedef compilation_check* compilation_check_ptr; + namespace lexer { struct token @@ -2233,6 +2384,19 @@ namespace exprtk } } + static inline std::string seperator_to_str(const token_type t) + { + switch (t) + { + case e_comma : return ","; + case e_colon : return ":"; + case e_eof : return ";"; + default : return "UNKNOWN"; + } + + return "UNKNOWN"; + } + inline bool is_error() const { return ( @@ -2282,7 +2446,7 @@ namespace exprtk s_itr_ = str.data(); s_end_ = str.data() + str.size(); - eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); + eof_token_.set_operator(token_t::e_eof, s_end_, s_end_, base_itr_); token_list_.clear(); while (!is_end(s_itr_)) @@ -2345,7 +2509,9 @@ namespace exprtk inline token_t& operator[](const std::size_t& index) { if (index < token_list_.size()) + { return token_list_[index]; + } else return eof_token_; } @@ -2353,7 +2519,9 @@ namespace exprtk inline token_t operator[](const std::size_t& index) const { if (index < token_list_.size()) + { return token_list_[index]; + } else return eof_token_; } @@ -2497,7 +2665,7 @@ namespace exprtk } } - ++s_itr_; + ++s_itr_; } if (2 == mode) @@ -2509,9 +2677,17 @@ namespace exprtk #endif } + inline bool next_is_digit(const details::char_cptr itr) const + { + return ((itr + 1) != s_end_) && + details::is_digit(*(itr + 1)); + } + inline void scan_token() { - if (details::is_whitespace(*s_itr_)) + const char_t c = *s_itr_; + + if (details::is_whitespace(c)) { skip_whitespace(); return; @@ -2521,34 +2697,39 @@ namespace exprtk skip_comments(); return; } - else if (details::is_operator_char(*s_itr_)) + else if (details::is_operator_char(c)) { scan_operator(); return; } - else if (details::is_letter(*s_itr_)) + else if (details::is_letter(c)) { scan_symbol(); return; } - else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) + else if (('.' == c) && !next_is_digit(s_itr_)) + { + scan_operator(); + return; + } + else if (details::is_digit(c) || ('.' == c)) { scan_number(); return; } - else if ('$' == (*s_itr_)) + else if ('$' == c) { scan_special_function(); return; } #ifndef exprtk_disable_string_capabilities - else if ('\'' == (*s_itr_)) + else if ('\'' == c) { scan_string(); return; } #endif - else if ('~' == (*s_itr_)) + else if ('~' == c) { token_t t; t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); @@ -2658,7 +2839,7 @@ namespace exprtk } token_t t; - t.set_symbol(initial_itr,s_itr_,base_itr_); + t.set_symbol(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); } @@ -2858,12 +3039,12 @@ namespace exprtk ((s_itr_ + 4) <= s_end_) ) { - const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1))); + const bool x_separator = ('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)) + if (!(x_separator && both_digits)) { t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); @@ -2903,8 +3084,8 @@ namespace exprtk } t.set_string( - parsed_string, - static_cast(std::distance(base_itr_,initial_itr))); + parsed_string, + static_cast(std::distance(base_itr_,initial_itr))); } token_list_.push_back(t); @@ -2945,7 +3126,8 @@ namespace exprtk { public: - virtual ~token_scanner() {} + virtual ~token_scanner() + {} explicit token_scanner(const std::size_t& stride) : stride_(stride) @@ -2972,7 +3154,7 @@ namespace exprtk if (!operator()(t0)) { - return i; + return 0; } } break; @@ -2984,7 +3166,7 @@ namespace exprtk if (!operator()(t0, t1)) { - return i; + return 0; } } break; @@ -2997,7 +3179,7 @@ namespace exprtk if (!operator()(t0, t1, t2)) { - return i; + return 0; } } break; @@ -3011,7 +3193,7 @@ namespace exprtk if (!operator()(t0, t1, t2, t3)) { - return i; + return 0; } } break; @@ -3019,7 +3201,7 @@ namespace exprtk } } - return (g.token_list_.size() - stride_ + 1); + return 0; } virtual bool operator() (const token&) @@ -3211,7 +3393,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) + for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) { token t; @@ -3227,7 +3409,7 @@ namespace exprtk ++changes; - i+=2; + i += 2; if (static_cast(i) >= (g.token_list_.size() - 1)) break; @@ -3253,7 +3435,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) + for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) { token t; @@ -3269,7 +3451,7 @@ namespace exprtk ++changes; - i+=3; + i += 3; if (static_cast(i) >= (g.token_list_.size() - 2)) break; @@ -3367,7 +3549,7 @@ namespace exprtk std::set ignore_set_; }; - class operator_joiner : public token_joiner + class operator_joiner exprtk_final : public token_joiner { public: @@ -3543,7 +3725,7 @@ namespace exprtk } }; - class bracket_checker : public lexer::token_scanner + class bracket_checker exprtk_final : public lexer::token_scanner { public: @@ -3554,7 +3736,7 @@ namespace exprtk , state_(true) {} - bool result() + bool result() exprtk_override { if (!stack_.empty()) { @@ -3575,7 +3757,7 @@ namespace exprtk return error_token_; } - void reset() + void reset() exprtk_override { // Why? because msvc doesn't support swap properly. stack_ = std::stack >(); @@ -3583,7 +3765,7 @@ namespace exprtk error_token_.clear(); } - bool operator() (const lexer::token& t) + bool operator() (const lexer::token& t) exprtk_override { if ( !t.value.empty() && @@ -3640,18 +3822,18 @@ namespace exprtk , current_index_(0) {} - bool result() + bool result() exprtk_override { return error_list_.empty(); } - void reset() + void reset() exprtk_override { error_list_.clear(); current_index_ = 0; } - bool operator() (const lexer::token& t) + bool operator() (const lexer::token& t) exprtk_override { if (token::e_number == t.type) { @@ -3692,7 +3874,7 @@ namespace exprtk std::vector error_list_; }; - class symbol_replacer : public lexer::token_modifier + class symbol_replacer exprtk_final : public lexer::token_modifier { private: @@ -3735,7 +3917,7 @@ namespace exprtk private: - bool modify(lexer::token& t) + bool modify(lexer::token& t) exprtk_override { if (lexer::token::e_symbol == t.type) { @@ -3798,12 +3980,12 @@ namespace exprtk add_invalid_set1(lexer::token::e_ternary); } - bool result() + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1) + bool operator() (const lexer::token& t0, const lexer::token& t1) exprtk_override { const set_t::value_type p = std::make_pair(t0.type,t1.type); @@ -3965,12 +4147,12 @@ namespace exprtk add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); } - bool result() + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) exprtk_override { const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); @@ -4227,6 +4409,11 @@ namespace exprtk return current_token_; } + inline const token_t& peek_next_token() + { + return lexer_.peek_next_token(); + } + enum token_advance_mode { e_hold = 0, @@ -4270,6 +4457,110 @@ namespace exprtk return true; } + inline bool token_is(const std::string& value, + const token_advance_mode mode = e_advance) + { + if (!exprtk::details::imatch(value,current_token().value)) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_arithmetic_opr(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_add : + case token_t::e_sub : + case token_t::e_div : + case token_t::e_mul : + case token_t::e_mod : + case token_t::e_pow : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_ineq_opr(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_eq : + case token_t::e_lte : + case token_t::e_ne : + case token_t::e_gte : + case token_t::e_lt : + case token_t::e_gt : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_left_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_lbracket : + case token_t::e_lcrlbracket : + case token_t::e_lsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_right_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_rbracket : + case token_t::e_rcrlbracket : + case token_t::e_rsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_rbracket : + case token_t::e_rcrlbracket : + case token_t::e_rsqrbracket : + case token_t::e_lbracket : + case token_t::e_lcrlbracket : + case token_t::e_lsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_loop(const token_advance_mode mode = e_advance) + { + return token_is("for" , mode) || + token_is("while" , mode) || + token_is("repeat", mode) ; + } + inline bool peek_token_is(const token_t::token_type& ttype) { return (lexer_.peek_next_token().type == ttype); @@ -4296,16 +4587,22 @@ namespace exprtk typedef T* data_ptr_t; vector_view(data_ptr_t data, const std::size_t& size) - : size_(size) + : base_size_(size) + , size_(size) , data_(data) , data_ref_(0) - {} + { + assert(size_ > 0); + } vector_view(const vector_view& vv) - : size_(vv.size_) + : base_size_(vv.base_size_) + , size_(vv.size_) , data_(vv.data_) , data_ref_(0) - {} + { + assert(size_ > 0); + } inline void rebase(data_ptr_t data) { @@ -4325,6 +4622,11 @@ namespace exprtk return data_; } + inline std::size_t base_size() const + { + return base_size_; + } + inline std::size_t size() const { return size_; @@ -4332,22 +4634,55 @@ namespace exprtk inline const T& operator[](const std::size_t index) const { + assert(index < size_); return data_[index]; } inline T& operator[](const std::size_t index) { + assert(index < size_); return data_[index]; } void set_ref(data_ptr_t* data_ref) { data_ref_.push_back(data_ref); + exprtk_debug(("vector_view::set_ref() - data_ref: %p data_ref_.size(): %d\n", + reinterpret_cast(data_ref), + static_cast(data_ref_.size()))); + } + + void remove_ref(data_ptr_t* data_ref) + { + data_ref_.erase( + std::remove(data_ref_.begin(), data_ref_.end(), data_ref), + data_ref_.end()); + exprtk_debug(("vector_view::remove_ref() - data_ref: %p data_ref_.size(): %d\n", + reinterpret_cast(data_ref), + static_cast(data_ref_.size()))); + } + + bool set_size(const std::size_t new_size) + { + if ((new_size > 0) && (new_size <= base_size_)) + { + size_ = new_size; + exprtk_debug(("vector_view::set_size() - data_: %p size: %lu\n", + reinterpret_cast(data_), + size_)); + return true; + } + + exprtk_debug(("vector_view::set_size() - error invalid new_size: %lu base_size: %lu\n", + new_size, + base_size_)); + return false; } private: - const std::size_t size_; + const std::size_t base_size_; + std::size_t size_; data_ptr_t data_; std::vector data_ref_; }; @@ -4523,6 +4858,16 @@ namespace exprtk return v_; } + inline operator value_t() const + { + return v_; + } + + inline operator value_t() + { + return v_; + } + template inline bool to_int(IntType& i) const { @@ -4571,6 +4916,9 @@ namespace exprtk public: typedef type_store type_store_t; + typedef typename type_store_t::scalar_view scalar_t; + typedef typename type_store_t::vector_view vector_t; + typedef typename type_store_t::string_view string_t; results_context() : results_available_(false) @@ -4594,6 +4942,61 @@ namespace exprtk return parameter_list_[index]; } + inline bool get_scalar(const std::size_t& index, T& out) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_scalar) + ) + { + const scalar_t scalar(parameter_list_[index]); + out = scalar(); + return true; + } + + return false; + } + + template + inline bool get_vector(const std::size_t& index, OutputIterator out_itr) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_vector) + ) + { + const vector_t vector(parameter_list_[index]); + for (std::size_t i = 0; i < vector.size(); ++i) + { + *(out_itr++) = vector[i]; + } + + return true; + } + + return false; + } + + inline bool get_vector(const std::size_t& index, std::vector& out) const + { + return get_vector(index,std::back_inserter(out)); + } + + inline bool get_string(const std::size_t& index, std::string& out) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_string) + ) + { + const string_t str(parameter_list_[index]); + out.assign(str.begin(),str.size()); + return true; + } + + return false; + } + private: inline void clear() @@ -4740,10 +5143,11 @@ namespace exprtk namespace loop_unroll { + const unsigned int global_loop_batch_size = #ifndef exprtk_disable_superscalar_unroll - const unsigned int global_loop_batch_size = 16; + 16; #else - const unsigned int global_loop_batch_size = 4; + 4; #endif struct details @@ -4770,11 +5174,28 @@ namespace exprtk ptr, static_cast(size))); else - exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + exprtk_debug(("%s - addr: %p\n", s.c_str(), ptr)); + } + + template + inline void dump_vector(const std::string& vec_name, const T* data, const std::size_t size) + { + printf("----- %s (%p) -----\n", + vec_name.c_str(), + static_cast(data)); + printf("[ "); + for (std::size_t i = 0; i < size; ++i) + { + printf("%8.3f\t", data[i]); + } + printf(" ]\n"); + printf("---------------------\n"); } #else inline void dump_ptr(const std::string&, const void*) {} inline void dump_ptr(const std::string&, const void*, const std::size_t) {} + template + inline void dump_vector(const std::string&, const T*, const std::size_t) {} #endif template @@ -4897,7 +5318,7 @@ namespace exprtk { if (this != &vds) { - std::size_t final_size = min_size(control_block_, vds.control_block_); + const std::size_t final_size = min_size(control_block_, vds.control_block_); vds.control_block_->size = final_size; control_block_->size = final_size; @@ -4947,7 +5368,7 @@ namespace exprtk if (5 == i) exprtk_debug(("\n")); - exprtk_debug(("%15.10f ",data()[i])); + exprtk_debug(("%15.10f ", data()[i])); } exprtk_debug(("\n")); #endif @@ -5060,8 +5481,8 @@ namespace exprtk case e_xnor : return xnor_opr(arg0,arg1); case e_root : return root (arg0,arg1); case e_roundn : return roundn (arg0,arg1); - case e_equal : return equal (arg0,arg1); - case e_nequal : return nequal (arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); case e_hypot : return hypot (arg0,arg1); case e_shr : return shr (arg0,arg1); case e_shl : return shl (arg0,arg1); @@ -5130,17 +5551,19 @@ namespace exprtk typedef Node** node_pp_t; typedef std::vector noderef_list_t; - virtual ~node_collector_interface() {} + virtual ~node_collector_interface() + {} - virtual void collect_nodes(noderef_list_t&) {} + virtual void collect_nodes(noderef_list_t&) + {} }; template struct node_depth_base; template - class expression_node : public node_collector_interface >, - public node_depth_base > + class expression_node : public node_collector_interface > + , public node_depth_base > { public: @@ -5177,12 +5600,14 @@ namespace exprtk e_vovovoc , e_vovocov , e_vocovov , e_covovov , e_covocov , e_vocovoc , e_covovoc , e_vococov , e_sf3ext , e_sf4ext , e_nulleq , e_strass , - e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , - e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , - e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , - e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , - e_valvecarith , e_vecunaryop , e_vecondition , e_break , - e_continue , e_swap + e_vector , e_vecsize , e_vecelem , e_veccelem , + e_vecelemrtc , e_veccelemrtc , e_rbvecelem , e_rbvecelemrtc , + e_rbveccelem , e_rbveccelemrtc , e_vecinit , e_vecvalass , + e_vecvecass , e_vecopvalass , e_vecopvecass , e_vecfunc , + e_vecvecswap , e_vecvecineq , e_vecvalineq , e_valvecineq , + e_vecvecarith , e_vecvalarith , e_valvecarith , e_vecunaryop , + e_vecondition , e_break , e_continue , e_swap , + e_assert }; typedef T value_type; @@ -5191,7 +5616,8 @@ namespace exprtk typedef typename nci_t::noderef_list_t noderef_list_t; typedef node_depth_base > ndb_t; - virtual ~expression_node() {} + virtual ~expression_node() + {} inline virtual T value() const { @@ -5207,6 +5633,11 @@ namespace exprtk { return e_none; } + + inline virtual bool valid() const + { + return true; + } }; // class expression_node template @@ -5251,6 +5682,12 @@ namespace exprtk return std::equal_to()(T(0),node.first->value()); } + template + inline bool is_literal_node(const expression_node* node) + { + return node && (details::expression_node::e_constant == node->type()); + } + template inline bool is_unary_node(const expression_node* node) { @@ -5280,10 +5717,15 @@ namespace exprtk { return node && ( - details::expression_node::e_variable == node->type() || - details::expression_node::e_vecelem == node->type() || - details::expression_node::e_rbvecelem == node->type() || - details::expression_node::e_rbveccelem == node->type() + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() || + details::expression_node::e_veccelem == node->type() || + details::expression_node::e_vecelemrtc == node->type() || + details::expression_node::e_veccelemrtc == node->type() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() || + details::expression_node::e_rbvecelemrtc == node->type() || + details::expression_node::e_rbveccelemrtc == node->type() ); } @@ -5293,12 +5735,42 @@ namespace exprtk return node && (details::expression_node::e_vecelem == node->type()); } + template + inline bool is_vector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_veccelem == node->type()); + } + + template + inline bool is_vector_elem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_vecelemrtc == node->type()); + } + + template + inline bool is_vector_celem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_veccelemrtc == node->type()); + } + template inline bool is_rebasevector_elem_node(const expression_node* node) { return node && (details::expression_node::e_rbvecelem == node->type()); } + template + inline bool is_rebasevector_elem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelemrtc == node->type()); + } + + template + inline bool is_rebasevector_celem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelemrtc == node->type()); + } + template inline bool is_rebasevector_celem_node(const expression_node* node) { @@ -5376,6 +5848,12 @@ namespace exprtk return node && (details::expression_node::e_function == node->type()); } + template + inline bool is_vararg_node(const expression_node* node) + { + return node && (details::expression_node::e_vararg == node->type()); + } + template inline bool is_return_node(const expression_node* node) { @@ -5396,7 +5874,13 @@ namespace exprtk } template - inline bool branch_deletable(expression_node* node) + inline bool is_assert_node(const expression_node* node) + { + return node && (details::expression_node::e_assert == node->type()); + } + + template + inline bool branch_deletable(const expression_node* node) { return (0 != node) && !is_variable_node(node) && @@ -5404,7 +5888,7 @@ namespace exprtk } template - inline bool all_nodes_valid(expression_node* (&b)[N]) + inline bool all_nodes_valid(expression_node* const (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { @@ -5428,7 +5912,7 @@ namespace exprtk } template - inline bool all_nodes_variables(expression_node* (&b)[N]) + inline bool all_nodes_variables(expression_node* const (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { @@ -5444,7 +5928,7 @@ namespace exprtk template class Sequence> - inline bool all_nodes_variables(Sequence*,Allocator>& b) + inline bool all_nodes_variables(const Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) { @@ -5478,7 +5962,7 @@ namespace exprtk 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(node))); + exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", reinterpret_cast(node))); delete node; node = reinterpret_cast(0); } @@ -5583,7 +6067,8 @@ namespace exprtk , depth(0) {} - virtual ~node_depth_base() {} + virtual ~node_depth_base() + {} virtual std::size_t node_depth() const { return 1; } @@ -5615,6 +6100,7 @@ namespace exprtk if (!depth_set) { depth = 0; + for (std::size_t i = 0; i < N; ++i) { if (branch[i].first) @@ -5622,6 +6108,7 @@ namespace exprtk depth = std::max(depth,branch[i].first->node_depth()); } } + depth += 1; depth_set = true; } @@ -5629,12 +6116,34 @@ namespace exprtk return depth; } + template + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1) const + { + return std::max(compute_node_depth(n0), compute_node_depth(n1)); + } + + template + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, const BranchType& n2) const + { + return std::max(compute_node_depth(n0), + std::max(compute_node_depth(n1), compute_node_depth(n2))); + } + + template + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2, const BranchType& n3) const + { + return std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + std::max(compute_node_depth(n2), compute_node_depth(n3))); + } + template 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 = 1 + max_node_depth(n0, n1); depth_set = true; } @@ -5647,9 +6156,7 @@ namespace exprtk { if (!depth_set) { - depth = 1 + std::max( - std::max(compute_node_depth(n0), compute_node_depth(n1)), - compute_node_depth(n2)); + depth = 1 + max_node_depth(n0, n1, n2); depth_set = true; } @@ -5662,9 +6169,7 @@ namespace exprtk { 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 = 1 + max_node_depth(n0, n1, n2, n3); depth_set = true; } @@ -5684,6 +6189,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i])); } } + depth_set = true; } @@ -5703,6 +6209,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i].first)); } } + depth_set = true; } @@ -5795,12 +6302,14 @@ namespace exprtk typedef Type value_type; typedef value_type* value_ptr; typedef const value_ptr const_value_ptr; + typedef vector_holder vector_holder_t; class vector_holder_base { public: - virtual ~vector_holder_base() {} + virtual ~vector_holder_base() + {} inline value_ptr operator[](const std::size_t& index) const { @@ -5812,6 +6321,11 @@ namespace exprtk return vector_size(); } + inline std::size_t base_size() const + { + return vector_base_size(); + } + inline value_ptr data() const { return value_at(0); @@ -5822,15 +6336,25 @@ namespace exprtk return false; } - virtual void set_ref(value_ptr*) {} + virtual void set_ref(value_ptr*) + {} + + virtual void remove_ref(value_ptr*) + {} + + virtual vector_view* rebaseable_instance() + { + return reinterpret_cast*>(0); + } protected: virtual value_ptr value_at(const std::size_t&) const = 0; virtual std::size_t vector_size() const = 0; + virtual std::size_t vector_base_size() const = 0; }; - class array_vector_impl : public vector_holder_base + class array_vector_impl exprtk_final : public vector_holder_base { public: @@ -5841,19 +6365,22 @@ namespace exprtk protected: - value_ptr value_at(const std::size_t& index) const + value_ptr value_at(const std::size_t& index) const exprtk_override { - if (index < size_) - return const_cast(vec_ + index); - else - return const_value_ptr(0); + assert(index < size_); + return const_cast(vec_ + index); } - std::size_t vector_size() const + std::size_t vector_size() const exprtk_override { return size_; } + std::size_t vector_base_size() const exprtk_override + { + return vector_size(); + } + private: array_vector_impl(const array_vector_impl&) exprtk_delete; @@ -5865,28 +6392,34 @@ namespace exprtk template class Sequence> - class sequence_vector_impl : public vector_holder_base + class sequence_vector_impl exprtk_final : public vector_holder_base { public: typedef Sequence sequence_t; - sequence_vector_impl(sequence_t& seq) + explicit sequence_vector_impl(sequence_t& seq) : sequence_(seq) {} protected: - value_ptr value_at(const std::size_t& index) const + value_ptr value_at(const std::size_t& index) const exprtk_override { - return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); + assert(index < sequence_.size()); + return (&sequence_[index]); } - std::size_t vector_size() const + std::size_t vector_size() const exprtk_override { return sequence_.size(); } + std::size_t vector_base_size() const exprtk_override + { + return vector_size(); + } + private: sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; @@ -5895,7 +6428,7 @@ namespace exprtk sequence_t& sequence_; }; - class vector_view_impl : public vector_holder_base + class vector_view_impl exprtk_final : public vector_holder_base { public: @@ -5903,30 +6436,48 @@ namespace exprtk vector_view_impl(vector_view_t& vec_view) : vec_view_(vec_view) - {} + { + assert(vec_view_.size() > 0); + } - void set_ref(value_ptr* ref) + void set_ref(value_ptr* ref) exprtk_override { vec_view_.set_ref(ref); } - virtual inline bool rebaseable() const + void remove_ref(value_ptr* ref) exprtk_override + { + vec_view_.remove_ref(ref); + } + + bool rebaseable() const exprtk_override { return true; } + vector_view* rebaseable_instance() exprtk_override + { + return &vec_view_; + } + protected: - value_ptr value_at(const std::size_t& index) const + value_ptr value_at(const std::size_t& index) const exprtk_override { - return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); + assert(index < vec_view_.size()); + return (&vec_view_[index]); } - std::size_t vector_size() const + std::size_t vector_size() const exprtk_override { return vec_view_.size(); } + std::size_t vector_base_size() const exprtk_override + { + return vec_view_.base_size(); + } + private: vector_view_impl(const vector_view_impl&) exprtk_delete; @@ -5935,6 +6486,62 @@ namespace exprtk vector_view_t& vec_view_; }; + class resizable_vector_impl exprtk_final : public vector_holder_base + { + public: + + resizable_vector_impl(vector_holder& vec_view_holder, + const Type* vec, + const std::size_t& vec_size) + : vec_(vec) + , size_(vec_size) + , vec_view_holder_(*vec_view_holder.rebaseable_instance()) + { + assert(vec_view_holder.rebaseable_instance()); + assert(size_ <= vector_base_size()); + } + + virtual ~resizable_vector_impl() + {} + + protected: + + value_ptr value_at(const std::size_t& index) const exprtk_override + { + assert(index < vector_size()); + return const_cast(vec_ + index); + } + + std::size_t vector_size() const exprtk_override + { + return vec_view_holder_.size(); + } + + std::size_t vector_base_size() const exprtk_override + { + return vec_view_holder_.base_size(); + } + + bool rebaseable() const exprtk_override + { + return true; + } + + virtual vector_view* rebaseable_instance() exprtk_override + { + return &vec_view_holder_; + } + + private: + + resizable_vector_impl(const resizable_vector_impl&) exprtk_delete; + resizable_vector_impl& operator=(const resizable_vector_impl&) exprtk_delete; + + const Type* vec_; + const std::size_t size_; + vector_view& vec_view_holder_; + }; + public: typedef typename details::vec_data_store vds_t; @@ -5956,6 +6563,10 @@ namespace exprtk : vector_holder_base_(new(buffer)vector_view_impl(vec)) {} + explicit vector_holder(vector_holder_t& vec_holder, const vds_t& vds) + : vector_holder_base_(new(buffer)resizable_vector_impl(vec_holder, vds.data(), vds.size())) + {} + inline value_ptr operator[](const std::size_t& index) const { return (*vector_holder_base_)[index]; @@ -5966,6 +6577,11 @@ namespace exprtk return vector_holder_base_->size(); } + inline std::size_t base_size() const + { + return vector_holder_base_->base_size(); + } + inline value_ptr data() const { return vector_holder_base_->data(); @@ -5973,7 +6589,18 @@ namespace exprtk void set_ref(value_ptr* ref) { - vector_holder_base_->set_ref(ref); + if (rebaseable()) + { + vector_holder_base_->set_ref(ref); + } + } + + void remove_ref(value_ptr* ref) + { + if (rebaseable()) + { + vector_holder_base_->remove_ref(ref); + } } bool rebaseable() const @@ -5981,8 +6608,16 @@ namespace exprtk return vector_holder_base_->rebaseable(); } + vector_view* rebaseable_instance() + { + return vector_holder_base_->rebaseable_instance(); + } + private: + vector_holder(const vector_holder&) exprtk_delete; + vector_holder& operator=(const vector_holder&) exprtk_delete; + mutable vector_holder_base* vector_holder_base_; uchar_t buffer[64]; }; @@ -6060,12 +6695,11 @@ namespace exprtk : equality_(equality) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); - const T v = branch_.first->value(); const bool result = details::numeric::is_nan(v); @@ -6085,6 +6719,11 @@ namespace exprtk return branch_.first; } + inline bool valid() const exprtk_override + { + return branch_.first; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -6146,7 +6785,8 @@ namespace exprtk typedef range_pack range_t; - virtual ~range_interface() {} + virtual ~range_interface() + {} virtual range_t& range_ref() = 0; @@ -6161,7 +6801,8 @@ namespace exprtk typedef range_data_type range_data_type_t; - virtual ~string_base_node() {} + virtual ~string_base_node() + {} virtual std::string str () const = 0; @@ -6172,9 +6813,9 @@ namespace exprtk template class string_literal_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -6183,8 +6824,8 @@ namespace exprtk explicit string_literal_node(const std::string& v) : value_(v) { - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.n0_c = std::make_pair(true, 0); + rp_.n1_c = std::make_pair(true, v.size()); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } @@ -6251,13 +6892,13 @@ namespace exprtk : operation_(opr) { construct_branch_pair(branch_,branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); - const T arg = branch_.first->value(); - return numeric::process(operation_,arg); + return numeric::process + (operation_,branch_.first->value()); } inline typename expression_node::node_type type() const exprtk_override @@ -6275,6 +6916,11 @@ namespace exprtk return branch_.first; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline void release() { branch_.second = false; @@ -6310,17 +6956,17 @@ namespace exprtk : operation_(opr) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - - return numeric::process(operation_, arg0, arg1); + return numeric::process + ( + operation_, + branch_[0].first->value(), + branch_[1].first->value() + ); } inline typename expression_node::node_type type() const exprtk_override @@ -6335,17 +6981,20 @@ namespace exprtk inline expression_node* branch(const std::size_t& index = 0) const exprtk_override { - if (0 == index) - return branch_[0].first; - else if (1 == index) - return branch_[1].first; - else - return reinterpret_cast(0); + assert(index < 2); + return branch_[index].first; + } + + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() ; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_final @@ -6370,16 +7019,13 @@ namespace exprtk binary_ext_node(expression_ptr branch0, expression_ptr branch1) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); - return Operation::process(arg0,arg1); } @@ -6395,17 +7041,20 @@ namespace exprtk inline expression_node* branch(const std::size_t& index = 0) const exprtk_override { - if (0 == index) - return branch_[0].first; - else if (1 == index) - return branch_[1].first; - else - return reinterpret_cast(0); + assert(index < 2); + return branch_[index].first; + } + + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() ; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -6433,14 +7082,11 @@ namespace exprtk : operation_(opr) { init_branches<3>(branch_, branch0, branch1, branch2); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - assert(branch_[2].first); - const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); @@ -6466,9 +7112,17 @@ namespace exprtk return expression_node::e_trinary; } + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() && + branch_[2].first && branch_[2].first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final @@ -6512,7 +7166,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final @@ -6520,6 +7174,15 @@ namespace exprtk return expression_node::ndb_t::template compute_node_depth<4>(branch_); } + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() && + branch_[2].first && branch_[2].first->valid() && + branch_[3].first && branch_[3].first->valid() ; + } + protected: operator_type operation_; @@ -6541,14 +7204,11 @@ namespace exprtk construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_ , consequent ); construct_branch_pair(alternative_, alternative); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_ .first); - assert(alternative_.first); - if (is_true(condition_)) return consequent_.first->value(); else @@ -6560,6 +7220,14 @@ namespace exprtk return expression_node::e_conditional; } + inline bool valid() const exprtk_override + { + return + condition_ .first && condition_ .first->valid() && + consequent_ .first && consequent_ .first->valid() && + alternative_.first && alternative_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6594,13 +7262,11 @@ namespace exprtk { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_, consequent); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_.first); - if (is_true(condition_)) return consequent_.first->value(); else @@ -6612,6 +7278,13 @@ namespace exprtk return expression_node::e_conditional; } + inline bool valid() const exprtk_override + { + return + condition_ .first && condition_ .first->valid() && + consequent_.first && consequent_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6653,7 +7326,7 @@ namespace exprtk typedef expression_node* expression_ptr; typedef std::pair branch_t; - break_node(expression_ptr ret = expression_ptr(0)) + explicit break_node(expression_ptr ret = expression_ptr(0)) { construct_branch_pair(return_, ret); } @@ -6666,7 +7339,7 @@ namespace exprtk throw break_exception(result); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits::quiet_NaN(); #endif } @@ -6699,7 +7372,7 @@ namespace exprtk inline T value() const exprtk_override { throw continue_exception(); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits::quiet_NaN(); #endif } @@ -6730,9 +7403,11 @@ namespace exprtk inline bool check() const { + assert(loop_runtime_check_); + if ( - (0 == loop_runtime_check_) || - ((++iteration_count_ <= max_loop_iterations_) && loop_runtime_check_->check()) + (++iteration_count_ <= max_loop_iterations_) && + loop_runtime_check_->check() ) { return true; @@ -6747,6 +7422,11 @@ namespace exprtk return false; } + bool valid() const + { + return 0 != loop_runtime_check_; + } + mutable _uint64_t iteration_count_; mutable loop_runtime_check_ptr loop_runtime_check_; const details::_uint64_t& max_loop_iterations_; @@ -6766,13 +7446,11 @@ namespace exprtk { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); while (is_true(condition_)) @@ -6788,6 +7466,13 @@ namespace exprtk return expression_node::e_while; } + inline bool valid() const exprtk_override + { + return + condition_.first && condition_.first->valid() && + loop_body_.first && loop_body_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6820,12 +7505,12 @@ namespace exprtk loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) - {} + { + assert(valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); T result = T(0); @@ -6838,6 +7523,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -6853,13 +7546,11 @@ namespace exprtk { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); do @@ -6876,6 +7567,13 @@ namespace exprtk return expression_node::e_repeat; } + inline bool valid() const exprtk_override + { + return + condition_.first && condition_.first->valid() && + loop_body_.first && loop_body_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6908,13 +7606,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } 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); @@ -6927,6 +7624,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -6946,13 +7651,11 @@ namespace exprtk construct_branch_pair(condition_ , condition ); construct_branch_pair(incrementor_, incrementor); construct_branch_pair(loop_body_ , loop_body ); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); if (initialiser_.first) @@ -6982,6 +7685,11 @@ namespace exprtk return expression_node::e_for; } + inline bool valid() const exprtk_override + { + return condition_.first && loop_body_.first; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(initialiser_ , node_delete_list); @@ -7021,13 +7729,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } 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(); @@ -7053,6 +7760,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; #ifndef exprtk_disable_break_continue @@ -7067,13 +7782,12 @@ namespace exprtk while_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : parent_t(condition, loop_body) - {} + { + assert(parent_t::valid()); + } 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_)) @@ -7109,13 +7823,12 @@ namespace exprtk loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) - {} + { + assert(valid()); + } 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(); @@ -7136,6 +7849,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -7149,13 +7870,12 @@ namespace exprtk repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : parent_t(condition, loop_body) - {} + { + assert(parent_t::valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); do @@ -7179,8 +7899,8 @@ namespace exprtk template class repeat_until_loop_bc_rtc_node exprtk_final - : public repeat_until_loop_bc_node, - public loop_runtime_checker + : public repeat_until_loop_bc_node + , public loop_runtime_checker { public: @@ -7192,13 +7912,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } 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(); @@ -7220,6 +7939,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -7235,13 +7962,12 @@ namespace exprtk expression_ptr incrementor, expression_ptr loop_body) : parent_t(initialiser, condition, incrementor, loop_body) - {} + { + assert(parent_t::valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); if (parent_t::initialiser_.first) @@ -7303,13 +8029,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } 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(); @@ -7354,6 +8079,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; #endif @@ -7376,7 +8109,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -7386,29 +8119,26 @@ namespace exprtk return; } } + + assert(valid()); } inline T value() const exprtk_override { - 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) { - const std::size_t upper_bound = (arg_list_.size() - 1); + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; - for (std::size_t i = 0; i < upper_bound; i += 2) + if (is_true(condition)) { - expression_ptr condition = arg_list_[i ].first; - expression_ptr consequent = arg_list_[i + 1].first; - - if (is_true(condition)) - { - return consequent->value(); - } + return consequent->value(); } - - return arg_list_[upper_bound].first->value(); } - else - return std::numeric_limits::quiet_NaN(); + + return arg_list_[upper_bound].first->value(); } inline typename expression_node::node_type type() const exprtk_override exprtk_final @@ -7416,6 +8146,11 @@ namespace exprtk return expression_node::e_switch; } + inline bool valid() const exprtk_override + { + return !arg_list_.empty(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -7469,7 +8204,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -7479,19 +8214,16 @@ namespace exprtk return; } } + + assert(valid()); } inline T value() const exprtk_override { - T result = T(0); - - if (arg_list_.empty()) - { - return std::numeric_limits::quiet_NaN(); - } - const std::size_t upper_bound = (arg_list_.size() - 1); + T result = T(0); + for (std::size_t i = 0; i < upper_bound; i += 2) { expression_ptr condition = arg_list_[i ].first; @@ -7511,6 +8243,11 @@ namespace exprtk return expression_node::e_mswitch; } + inline bool valid() const exprtk_override + { + return !arg_list_.empty() && (0 == (arg_list_.size() % 2)); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -7531,7 +8268,8 @@ namespace exprtk { public: - virtual ~ivariable() {} + virtual ~ivariable() + {} virtual T& ref() = 0; virtual const T& ref() const = 0; @@ -7539,8 +8277,8 @@ namespace exprtk template class variable_node exprtk_final - : public expression_node, - public ivariable + : public expression_node + , public ivariable { public: @@ -7677,7 +8415,7 @@ namespace exprtk (std::numeric_limits::max() == r1 ) ) { - r1 = size - 1; + r1 = size; } cache.first = r0; @@ -7692,12 +8430,12 @@ namespace exprtk inline std::size_t const_size() const { - return (n1_c.second - n0_c.second + 1); + return (n1_c.second - n0_c.second); } inline std::size_t cache_size() const { - return (cache.second - cache.first + 1); + return (cache.second - cache.first); } std::pair n0_e; @@ -7711,16 +8449,20 @@ namespace exprtk const std::size_t r1, const std::size_t size) const { - if (r0 >= size) + if (r0 > size) { - throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); + throw std::runtime_error("range error: (r0 < 0) || (r0 > size)"); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return false; + #endif } - if (r1 >= size) + if (r1 > size) { - throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); + throw std::runtime_error("range error: (r1 < 0) || (r1 > size)"); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return false; + #endif } return (r0 <= r1); @@ -7762,19 +8504,22 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; - virtual ~vector_interface() {} + virtual ~vector_interface() + {} + + virtual std::size_t size () const = 0; - virtual std::size_t size () const = 0; + virtual std::size_t base_size() const = 0; - virtual vector_node_ptr vec() const = 0; + virtual vector_node_ptr vec () const = 0; - virtual vector_node_ptr vec() = 0; + virtual vector_node_ptr vec () = 0; - virtual vds_t& vds () = 0; + virtual vds_t& vds () = 0; - virtual const vds_t& vds () const = 0; + virtual const vds_t& vds () const = 0; - virtual bool side_effect () const { return false; } + virtual bool side_effect () const { return false; } }; template @@ -7801,6 +8546,12 @@ namespace exprtk , vds_(vds) {} + ~vector_node() + { + assert(valid()); + vector_holder_->remove_ref(&vds_.ref()); + } + inline T value() const exprtk_override { return vds().data()[0]; @@ -7821,9 +8572,19 @@ namespace exprtk return expression_node::e_vector; } + inline bool valid() const exprtk_override + { + return vector_holder_; + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -7841,16 +8602,65 @@ namespace exprtk return (*vector_holder_); } + inline vector_holder_t& vec_holder() const + { + return (*vector_holder_); + } + private: vector_holder_t* vector_holder_; vds_t vds_; }; + template + class vector_size_node exprtk_final + : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + + explicit vector_size_node(vector_holder_t* vh) + : vector_holder_(vh) + {} + + ~vector_size_node() + { + assert(valid()); + } + + inline T value() const exprtk_override + { + assert(vector_holder_); + return static_cast(vector_holder_->size()); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecsize; + } + + inline bool valid() const exprtk_override + { + return vector_holder_ && vector_holder_->size(); + } + + inline vector_holder_t* vec_holder() + { + return vector_holder_; + } + + private: + + vector_holder_t* vector_holder_; + }; + template class vector_elem_node exprtk_final - : public expression_node, - public ivariable + : public expression_node + , public ivariable { public: @@ -7859,26 +8669,30 @@ namespace exprtk typedef vector_holder_t* vector_holder_ptr; typedef std::pair branch_t; - vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : vec_holder_(vec_holder) + vector_elem_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) , vector_base_((*vec_holder)[0]) { - construct_branch_pair(index_, index); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override @@ -7886,67 +8700,96 @@ namespace exprtk return expression_node::e_vecelem; } + inline bool valid() const exprtk_override + { + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); + } + inline vector_holder_t& vec_holder() { - return (*vec_holder_); + return (*vector_holder_); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::collect(index_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_ , node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(index_); + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } private: - vector_holder_ptr vec_holder_; + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_base_ + details::numeric::to_uint64(index_.first->value())); + } + + vector_holder_ptr vector_holder_; T* vector_base_; + branch_t vector_node_; branch_t index_; }; template - class rebasevector_elem_node exprtk_final - : public expression_node, - public ivariable + class vector_celem_node exprtk_final + : public expression_node + , public ivariable { public: typedef expression_node* expression_ptr; typedef vector_holder vector_holder_t; typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; typedef std::pair branch_t; - rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : vector_holder_(vec_holder) - , vds_((*vector_holder_).size(),(*vector_holder_)[0]) + vector_celem_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) { - vector_holder_->set_ref(&vds_.ref()); - construct_branch_pair(index_, index); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_rbvecelem; + return expression_node::e_veccelem; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } inline vector_holder_t& vec_holder() @@ -7956,59 +8799,82 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(index_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(index_); + return expression_node::ndb_t::compute_node_depth(vector_node_); } private: + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_base_ + index_); + } + + const std::size_t index_; vector_holder_ptr vector_holder_; - vds_t vds_; - branch_t index_; + T* vector_base_; + branch_t vector_node_; }; template - class rebasevector_celem_node exprtk_final - : public expression_node, - public ivariable + class vector_elem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) - : index_(index) - , vector_holder_(vec_holder) - , vds_((*vector_holder_).size(),(*vector_holder_)[0]) + vector_elem_rtc_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) + , max_vector_index_(vector_holder_->size() - 1) { - vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_rbveccelem; + return expression_node::e_vecelemrtc; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } inline vector_holder_t& vec_holder() @@ -8016,451 +8882,1432 @@ namespace exprtk return (*vector_holder_); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); + } + private: - const std::size_t index_; + inline T* access_vector() const + { + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); + vector_node_.first->value(); + + if (index <= max_vector_index_) + { + return (vector_holder_->data() + index); + } + + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_base_ ; + } + vector_holder_ptr vector_holder_; - vds_t vds_; + T* vector_base_; + branch_t vector_node_; + branch_t index_; + vector_access_runtime_check_ptr vec_rt_chk_; + const std::size_t max_vector_index_; }; template - class vector_assignment_node exprtk_final : public expression_node + class vector_celem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - vector_assignment_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base) - , initialiser_list_(initialiser_list) - , size_(size) - , single_value_initialse_(single_value_initialse) - {} + vector_celem_rtc_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : index_(index) + , max_vector_index_(vec_holder->size() - 1) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) + { + construct_branch_pair(vector_node_, vec_node); + assert(valid()); + } inline T value() const exprtk_override { - if (single_value_initialse_) - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = initialiser_list_[0]->value(); - } - } - else - { - const std::size_t initialiser_list_size = initialiser_list_.size(); - - for (std::size_t i = 0; i < initialiser_list_size; ++i) - { - *(vector_base_ + i) = initialiser_list_[i]->value(); - } + return *access_vector(); + } - if (initialiser_list_size < size_) - { - for (std::size_t i = initialiser_list_size; i < size_; ++i) - { - *(vector_base_ + i) = T(0); - } - } - } + inline T& ref() exprtk_override + { + return *access_vector(); + } - return *(vector_base_); + inline const T& ref() const exprtk_override + { + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_vecdefass; + return expression_node::e_veccelemrtc; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); + return expression_node::ndb_t::compute_node_depth(vector_node_); } private: - vector_assignment_node(const vector_assignment_node&) exprtk_delete; - vector_assignment_node& operator=(const vector_assignment_node&) exprtk_delete; + inline T* access_vector() const + { + vector_node_.first->value(); - mutable T* vector_base_; - std::vector initialiser_list_; - const std::size_t size_; - const bool single_value_initialse_; + if (index_ <= max_vector_index_) + { + return (vector_holder_->data() + index_); + } + + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_base_ ; + } + + const std::size_t index_; + const std::size_t max_vector_index_; + vector_holder_ptr vector_holder_; + T* vector_base_; + branch_t vector_node_; + vector_access_runtime_check_ptr vec_rt_chk_; }; template - class swap_node exprtk_final : public expression_node + class rebasevector_elem_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; - typedef variable_node* variable_node_ptr; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair branch_t; - swap_node(variable_node_ptr var0, variable_node_ptr var1) - : var0_(var0) - , var1_(var1) - {} + rebasevector_elem_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) + { + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); + } inline T value() const exprtk_override { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + return *access_vector(); } - inline typename expression_node::node_type type() const exprtk_override + inline T& ref() exprtk_override { - return expression_node::e_swap; + return *access_vector(); } - private: - - variable_node_ptr var0_; - variable_node_ptr var1_; - }; + inline const T& ref() const exprtk_override + { + return *access_vector(); + } - template - class swap_generic_node exprtk_final : public binary_node - { - public: + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_rbvecelem; + } - typedef expression_node* expression_ptr; - typedef ivariable* ivariable_ptr; + inline bool valid() const exprtk_override + { + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); + } - swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node(details::e_swap, var0, var1) - , var0_(dynamic_cast(var0)) - , var1_(dynamic_cast(var1)) - {} + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } - inline T value() const exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_, node_delete_list); } - inline typename expression_node::node_type type() const exprtk_override + std::size_t node_depth() const exprtk_override { - return expression_node::e_swap; + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } private: - ivariable_ptr var0_; - ivariable_ptr var1_; + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_holder_->data() + details::numeric::to_uint64(index_.first->value())); + } + + vector_holder_ptr vector_holder_; + branch_t vector_node_; + branch_t index_; }; template - class swap_vecvec_node exprtk_final - : public binary_node - , public vector_interface + class rebasevector_celem_node exprtk_final + : public expression_node + , public ivariable { public: typedef expression_node* expression_ptr; - typedef vector_node * vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - swap_vecvec_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , vec_size_ (0) - , initialised_ (false) + rebasevector_celem_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) { - if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - vds() = vi->vds(); - } - } - - if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - 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; - } - - assert(initialised_); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - binary_node::branch(0)->value(); - binary_node::branch(1)->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::quiet_NaN(); + vector_node_.first->value(); + return ref();; } - vector_node_ptr vec() const exprtk_override + inline T& ref() exprtk_override { - return vec0_node_ptr_; + return *(vector_holder_->data() + index_); } - vector_node_ptr vec() exprtk_override + inline const T& ref() const exprtk_override { - return vec0_node_ptr_; + return *(vector_holder_->data() + index_); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_vecvecswap; + return expression_node::e_rbveccelem; } - std::size_t size() const exprtk_override + inline bool valid() const exprtk_override { - return vec_size_; + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - vds_t& vds() exprtk_override + inline vector_holder_t& vec_holder() { - return vds_; + return (*vector_holder_); } - const vds_t& vds() const exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return vds_; + expression_node::ndb_t::collect(vector_node_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(vector_node_); } private: - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - std::size_t vec_size_; - bool initialised_; - vds_t vds_; + const std::size_t index_; + vector_holder_ptr vector_holder_; + branch_t vector_node_; }; - #ifndef exprtk_disable_string_capabilities template - class stringvar_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + class rebasevector_elem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef typename range_interface::range_t range_t; - - static std::string null_value; - - explicit stringvar_node() - : value_(&null_value) - {} - - explicit stringvar_node(std::string& v) - : value_(&v) - { - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,v.size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - inline bool operator <(const stringvar_node& v) const + rebasevector_elem_rtc_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : vector_holder_(vec_holder) + , vec_rt_chk_(vec_rt_chk) { - return this < (&v); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - rp_.n1_c.second = (*value_).size() - 1; - rp_.cache.second = rp_.n1_c.second; - - return std::numeric_limits::quiet_NaN(); + return *access_vector(); } - std::string str() const exprtk_override + inline T& ref() exprtk_override { - return ref(); + return *access_vector(); } - char_cptr base() const exprtk_override + inline const T& ref() const exprtk_override { - return &(*value_)[0]; + return *access_vector(); } - std::size_t size() const exprtk_override + inline typename expression_node::node_type type() const exprtk_override { - return ref().size(); + return expression_node::e_rbvecelemrtc; } - std::string& ref() + inline bool valid() const exprtk_override { - return (*value_); + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } - const std::string& ref() const + inline vector_holder_t& vec_holder() { - return (*value_); + return (*vector_holder_); } - range_t& range_ref() exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return rp_; + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_ , node_delete_list); } - const range_t& range_ref() const exprtk_override + std::size_t node_depth() const exprtk_override { - return rp_; + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvar; - } + private: - void rebase(std::string& s) + inline T* access_vector() const { - value_ = &s; - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,value_->size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } + vector_node_.first->value(); + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); - private: + if (index <= (vector_holder_->size() - 1)) + { + return (vector_holder_->data() + index); + } - std::string* value_; - mutable range_t rp_; - }; + assert(vec_rt_chk_); - template - std::string stringvar_node::null_value = std::string(""); + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_holder_->data()); + context.end_ptr = reinterpret_cast(vector_holder_->data() + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_holder_->data() + index); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_holder_->data() ; + } + + vector_holder_ptr vector_holder_; + branch_t vector_node_; + branch_t index_; + vector_access_runtime_check_ptr vec_rt_chk_; + }; template - class string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + class rebasevector_celem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef typename range_interface::range_t range_t; - - static std::string null_value; - - explicit string_range_node(std::string& v, const range_t& rp) - : value_(&v) - , rp_(rp) - {} - - virtual ~string_range_node() - { - rp_.free(); - } + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - inline bool operator <(const string_range_node& v) const + rebasevector_celem_rtc_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : index_(index) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) { - return this < (&v); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - return std::numeric_limits::quiet_NaN(); + return *access_vector(); } - inline std::string str() const exprtk_override + inline T& ref() exprtk_override { - return (*value_); + return *access_vector(); } - char_cptr base() const exprtk_override + inline const T& ref() const exprtk_override { - return &(*value_)[0]; + return *access_vector(); } - std::size_t size() const exprtk_override + inline typename expression_node::node_type type() const exprtk_override { - return ref().size(); + return expression_node::e_rbveccelemrtc; } - inline range_t range() const + inline bool valid() const exprtk_override { - return rp_; + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - inline virtual std::string& ref() + inline vector_holder_t& vec_holder() { - return (*value_); + return (*vector_holder_); } - inline virtual const std::string& ref() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return (*value_); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } - inline range_t& range_ref() exprtk_override + std::size_t node_depth() const exprtk_override { - return rp_; + return expression_node::ndb_t::compute_node_depth(vector_node_); } - inline const range_t& range_ref() const exprtk_override - { - return rp_; - } + private: - inline typename expression_node::node_type type() const exprtk_override + inline T* access_vector() const { - return expression_node::e_stringvarrng; - } + vector_node_.first->value(); - private: + if (index_ <= vector_holder_->size() - 1) + { + return (vector_holder_->data() + index_); + } - std::string* value_; - range_t rp_; + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_base_ ; + } + + const std::size_t index_; + vector_holder_ptr vector_holder_; + T* vector_base_; + branch_t vector_node_; + vector_access_runtime_check_ptr vec_rt_chk_; }; template - std::string string_range_node::null_value = std::string(""); + class vector_initialisation_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_initialisation_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base) + , initialiser_list_(initialiser_list) + , size_(size) + , single_value_initialse_(single_value_initialse) + , zero_value_initialse_(false) + , const_nonzero_literal_value_initialse_(false) + , single_initialiser_value_(T(0)) + { + if (single_value_initialse_) + { + if (initialiser_list_.empty()) + zero_value_initialse_ = true; + else if ( + (initialiser_list_.size() == 1) && + details::is_constant_node(initialiser_list_[0]) && + (T(0) == initialiser_list_[0]->value()) + ) + { + zero_value_initialse_ = true; + } + else + { + assert(initialiser_list_.size() == 1); + + if (details::is_constant_node(initialiser_list_[0])) + { + const_nonzero_literal_value_initialse_ = true; + single_initialiser_value_ = initialiser_list_[0]->value(); + assert(T(0) != single_initialiser_value_); + } + } + } + } + + inline T value() const exprtk_override + { + if (single_value_initialse_) + { + if (zero_value_initialse_) + { + details::set_zero_value(vector_base_, size_); + } + else if (const_nonzero_literal_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = single_initialiser_value_; + } + } + else + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + } + else + { + const std::size_t initialiser_list_size = initialiser_list_.size(); + + for (std::size_t i = 0; i < initialiser_list_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (initialiser_list_size < size_) + { + details::set_zero_value( + vector_base_ + initialiser_list_size, + (size_ - initialiser_list_size)); + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_initialisation_node(const vector_initialisation_node&) exprtk_delete; + vector_initialisation_node& operator=(const vector_initialisation_node&) exprtk_delete; + + mutable T* vector_base_; + std::vector initialiser_list_; + const std::size_t size_; + const bool single_value_initialse_; + bool zero_value_initialse_; + bool const_nonzero_literal_value_initialse_; + T single_initialiser_value_; + }; + + template + class vector_init_zero_value_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_zero_value_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + {} + + inline T value() const exprtk_override + { + details::set_zero_value(vector_base_, size_); + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_zero_value_node(const vector_init_zero_value_node&) exprtk_delete; + vector_init_zero_value_node& operator=(const vector_init_zero_value_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_single_constvalue_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_single_constvalue_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + single_initialiser_value_ = initialiser_list_[0]->value(); + assert(valid()); + } + + inline T value() const exprtk_override + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = single_initialiser_value_; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 1) && + (details::is_constant_node(initialiser_list_[0])) && + (single_initialiser_value_ != T(0)); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_single_constvalue_node(const vector_init_single_constvalue_node&) exprtk_delete; + vector_init_single_constvalue_node& operator=(const vector_init_single_constvalue_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T single_initialiser_value_; + }; + + template + class vector_init_single_value_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_single_value_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + expression_node& node = *initialiser_list_[0]; + + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = node.value(); + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 1) && + !details::is_constant_node(initialiser_list_[0]); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_single_value_node(const vector_init_single_value_node&) exprtk_delete; + vector_init_single_value_node& operator=(const vector_init_single_value_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_iota_constconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_constconst_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + base_value_ = initialiser_list_[0]->value(); + increment_value_ = initialiser_list_[1]->value(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = base_value_; + + for (std::size_t i = 0; i < size_; ++i, value += increment_value_) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (details::is_constant_node(initialiser_list_[0])) && + (details::is_constant_node(initialiser_list_[1])) ; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constconst_node(const vector_init_iota_constconst_node&) exprtk_delete; + vector_init_iota_constconst_node& operator=(const vector_init_iota_constconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T base_value_; + T increment_value_; + }; + + template + class vector_init_iota_constnconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_constnconst_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + base_value_ = initialiser_list_[0]->value(); + } + + inline T value() const exprtk_override + { + T value = base_value_; + expression_node& increment = *initialiser_list_[1]; + + for (std::size_t i = 0; i < size_; ++i, value += increment.value()) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + ( details::is_constant_node(initialiser_list_[0])) && + (!details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constnconst_node(const vector_init_iota_constnconst_node&) exprtk_delete; + vector_init_iota_constnconst_node& operator=(const vector_init_iota_constnconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T base_value_; + }; + + template + class vector_init_iota_nconstconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_nconstconst_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = initialiser_list_[0]->value(); + const T increment = initialiser_list_[1]->value(); + + for (std::size_t i = 0; i < size_; ++i, value += increment) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (!details::is_constant_node(initialiser_list_[0])) && + (details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstconst_node(const vector_init_iota_nconstconst_node&) exprtk_delete; + vector_init_iota_nconstconst_node& operator=(const vector_init_iota_nconstconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_iota_nconstnconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_nconstnconst_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = initialiser_list_[0]->value(); + expression_node& increment = *initialiser_list_[1]; + + for (std::size_t i = 0; i < size_; ++i, value += increment.value()) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (!details::is_constant_node(initialiser_list_[0])) && + (!details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstnconst_node(const vector_init_iota_nconstnconst_node&) exprtk_delete; + vector_init_iota_nconstnconst_node& operator=(const vector_init_iota_nconstnconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class swap_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef variable_node* variable_node_ptr; + + swap_node(variable_node_ptr var0, variable_node_ptr var1) + : var0_(var0) + , var1_(var1) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template + class swap_generic_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + typedef ivariable* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : binary_node(details::e_swap, var0, var1) + , var0_(dynamic_cast(var0)) + , var1_(dynamic_cast(var1)) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + }; + + template + class swap_vecvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node * vector_node_ptr; + typedef vec_data_store vds_t; + + using binary_node::branch; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_ (false) + { + if (is_ivector_node(branch(0))) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(branch(0)))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } + } + + if (is_ivector_node(branch(1))) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(branch(1)))) + { + vec1_node_ptr_ = vi->vec(); + } + } + + if (vec0_node_ptr_ && vec1_node_ptr_) + { + initialised_ = size() <= base_size(); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + binary_node::branch(0)->value(); + binary_node::branch(1)->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + assert(size() <= base_size()); + const std::size_t n = size(); + + for (std::size_t i = 0; i < n; ++i) + { + std::swap(vec0[i],vec1[i]); + } + + return vec1_node_ptr_->value(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecvecswap; + } + + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + + std::size_t size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class stringvar_node exprtk_final + : public expression_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + static std::string null_value; + + explicit stringvar_node() + : value_(&null_value) + {} + + explicit stringvar_node(std::string& v) + : value_(&v) + { + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,v.size()); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline bool operator <(const stringvar_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + rp_.n1_c.second = (*value_).size(); + rp_.cache.second = rp_.n1_c.second; + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return ref(); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + std::string& ref() + { + return (*value_); + } + + const std::string& ref() const + { + return (*value_); + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvar; + } + + void rebase(std::string& s) + { + value_ = &s; + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,value_->size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + private: + + std::string* value_; + mutable range_t rp_; + }; + + template + std::string stringvar_node::null_value = std::string(""); + + template + class string_range_node exprtk_final + : public expression_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + static std::string null_value; + + explicit string_range_node(std::string& v, const range_t& rp) + : value_(&v) + , rp_(rp) + {} + + virtual ~string_range_node() + { + rp_.free(); + } + + inline bool operator <(const string_range_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + return std::numeric_limits::quiet_NaN(); + } + + inline std::string str() const exprtk_override + { + return (*value_); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + inline range_t range() const + { + return rp_; + } + + inline virtual std::string& ref() + { + return (*value_); + } + + inline virtual const std::string& ref() const + { + return (*value_); + } + + inline range_t& range_ref() exprtk_override + { + return rp_; + } + + inline const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_stringvarrng; + } + + private: + + std::string* value_; + range_t rp_; + }; + + template + std::string string_range_node::null_value = std::string(""); template class const_string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -8527,9 +10374,9 @@ namespace exprtk template class generic_string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -8569,8 +10416,7 @@ namespace exprtk } initialised_ = (str_base_ptr_ && str_range_ptr_); - - assert(initialised_); + assert(valid()); } ~generic_string_range_node() @@ -8580,34 +10426,184 @@ namespace exprtk inline T value() const exprtk_override { - if (initialised_) + 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; + + const range_t& range = str_range_ptr_->range_ref(); + + const std::size_t base_str_size = str_base_ptr_->size(); + + if ( + range (str_r0, str_r1, base_str_size ) && + base_range_(r0 , r1 , base_str_size - str_r0) + ) { - assert(branch_.first); + const std::size_t size = r1 - r0; - branch_.first->value(); + range_.n1_c.second = size; + range_.cache.second = range_.n1_c.second; - std::size_t str_r0 = 0; - std::size_t str_r1 = 0; + value_.assign(str_base_ptr_->base() + str_r0 + r0, size); + } - std::size_t r0 = 0; - std::size_t r1 = 0; + return std::numeric_limits::quiet_NaN(); + } - const range_t& range = str_range_ptr_->range_ref(); + std::string str() const exprtk_override + { + return value_; + } - const std::size_t base_str_size = str_base_ptr_->size(); + char_cptr base() const exprtk_override + { + return &value_[0]; + } - if ( - range (str_r0, str_r1, base_str_size) && - base_range_( r0, r1, base_str_size - str_r0) - ) - { - const std::size_t size = (r1 - r0) + 1; + std::size_t size() const exprtk_override + { + return value_.size(); + } - range_.n1_c.second = size - 1; - range_.cache.second = range_.n1_c.second; + range_t& range_ref() exprtk_override + { + return range_; + } - value_.assign(str_base_ptr_->base() + str_r0 + r0, size); - } + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strgenrange; + } + + inline bool valid() const exprtk_override + { + return initialised_ && branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bool initialised_; + 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_; + }; + + template + class string_concat_node exprtk_final + : public binary_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef range_t* range_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + using binary_node::branch; + + string_concat_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(branch(0))) + { + str0_base_ptr_ = dynamic_cast(branch(0)); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(branch(0)); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(branch(1))) + { + str1_base_ptr_ = dynamic_cast(branch(1)); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(branch(1)); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + assert(valid()); + } + + inline T value() const exprtk_override + { + branch(0)->value(); + branch(1)->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; + + const range_t& range0 = str0_range_ptr_->range_ref(); + const range_t& range1 = str1_range_ptr_->range_ref(); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = (str0_r1 - str0_r0); + const std::size_t size1 = (str1_r1 - str1_r0); + + value_.assign(str0_base_ptr_->base() + str0_r0, size0); + value_.append(str1_base_ptr_->base() + str1_r0, size1); + + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; } return std::numeric_limits::quiet_NaN(); @@ -8640,163 +10636,12 @@ namespace exprtk inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_strgenrange; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bool initialised_; - 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_; - }; - - template - class string_concat_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef range_t* range_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - string_concat_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , initialised_(false) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_range_ptr_(0) - , str1_range_ptr_(0) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(branch(0))) - { - str0_base_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_range_ptr_) - return; - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - str1_range_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(initialised_); - } - - inline T value() const exprtk_override - { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->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; - - const range_t& range0 = str0_range_ptr_->range_ref(); - const range_t& range1 = str1_range_ptr_->range_ref(); - - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size0 = (str0_r1 - str0_r0) + 1; - const std::size_t size1 = (str1_r1 - str1_r0) + 1; - - value_.assign(str0_base_ptr_->base() + str0_r0, size0); - value_.append(str1_base_ptr_->base() + str1_r0, size1); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; - } - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return &value_[0]; - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t& range_ref() exprtk_override - { - return range_; - } - - const range_t& range_ref() const exprtk_override - { - return range_; + return expression_node::e_strconcat; } - inline typename expression_node::node_type type() const exprtk_override + inline bool valid() const exprtk_override { - return expression_node::e_strconcat; + return initialised_ && binary_node::valid(); } private: @@ -8812,9 +10657,9 @@ namespace exprtk template class swap_string_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -8829,10 +10674,10 @@ namespace exprtk using binary_node::branch; swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1), - initialised_(false), - str0_node_ptr_(0), - str1_node_ptr_(0) + : binary_node(details::e_swap, branch0, branch1) + , initialised_(false) + , str0_node_ptr_(0) + , str1_node_ptr_(0) { if (is_string_node(branch(0))) { @@ -8845,22 +10690,15 @@ namespace exprtk } initialised_ = (str0_node_ptr_ && str1_node_ptr_); - - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->value(); - std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); - } + std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); return std::numeric_limits::quiet_NaN(); } @@ -8895,6 +10733,11 @@ namespace exprtk return expression_node::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -8960,87 +10803,81 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); + branch(0)->value(); + branch(1)->value(); - branch(0)->value(); - branch(1)->value(); + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = range0.cache_size(); + const std::size_t size1 = range1.cache_size(); + const std::size_t max_size = std::min(size0,size1); - 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(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); - char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); - char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); + loop_unroll::details lud(max_size); + char_cptr upper_bound = s0 + lud.upper_bound; - 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]); \ - 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; - } + 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 - int i = 0; + s0 += lud.batch_size; + s1 += lud.batch_size; + } - 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 + int i = 0; - #undef exprtk_loop - #undef case_stmt + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ + exprtk_fallthrough \ + + #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) + default: break; } + + #undef exprtk_loop + #undef case_stmt } return std::numeric_limits::quiet_NaN(); @@ -9051,6 +10888,11 @@ namespace exprtk return expression_node::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; @@ -9068,7 +10910,7 @@ namespace exprtk { public: - static std::string null_value; + static const std::string null_value; explicit stringvar_size_node() : value_(&null_value) @@ -9090,11 +10932,11 @@ namespace exprtk private: - std::string* value_; + const std::string* value_; }; template - std::string stringvar_size_node::null_value = std::string(""); + const std::string stringvar_size_node::null_value = std::string(""); template class string_size_node exprtk_final : public expression_node @@ -9113,23 +10955,15 @@ namespace exprtk if (is_generally_string_node(branch_.first)) { str_base_ptr_ = dynamic_cast(branch_.first); - - if (0 == str_base_ptr_) - return; } + + assert(valid()); } inline T value() const exprtk_override { - T result = std::numeric_limits::quiet_NaN(); - - if (str_base_ptr_) - { - branch_.first->value(); - result = T(str_base_ptr_->size()); - } - - return result; + branch_.first->value(); + return T(str_base_ptr_->size()); } inline typename expression_node::node_type type() const exprtk_override @@ -9137,6 +10971,11 @@ namespace exprtk return expression_node::e_stringsize; } + inline bool valid() const exprtk_override + { + return str_base_ptr_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -9149,7 +10988,7 @@ namespace exprtk private: - branch_t branch_; + branch_t branch_; str_base_ptr str_base_ptr_; }; @@ -9167,9 +11006,9 @@ namespace exprtk template class assignment_string_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9219,31 +11058,25 @@ namespace exprtk str0_node_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); + branch(1)->value(); - branch(1)->value(); - - std::size_t r0 = 0; - std::size_t r1 = 0; + std::size_t r0 = 0; + std::size_t r1 = 0; - const range_t& range = (*str1_range_ptr_); + const range_t& range = (*str1_range_ptr_); - if (range(r0, r1, str1_base_ptr_->size())) - { - AssignmentProcess::execute(str0_node_ptr_->ref(), - str1_base_ptr_->base() + r0, - (r1 - r0) + 1); + if (range(r0, r1, str1_base_ptr_->size())) + { + AssignmentProcess::execute( + str0_node_ptr_->ref(), + str1_base_ptr_->base() + r0, (r1 - r0)); - branch(0)->value(); - } + branch(0)->value(); } return std::numeric_limits::quiet_NaN(); @@ -9279,6 +11112,11 @@ namespace exprtk return expression_node::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -9290,9 +11128,9 @@ namespace exprtk template class assignment_string_range_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9351,39 +11189,34 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); + branch(0)->value(); + branch(1)->value(); - branch(0)->value(); - branch(1)->value(); - - std::size_t s0_r0 = 0; - std::size_t s0_r1 = 0; + std::size_t s0_r0 = 0; + std::size_t s0_r1 = 0; - std::size_t s1_r0 = 0; - std::size_t s1_r1 = 0; + std::size_t s1_r0 = 0; + std::size_t s1_r1 = 0; - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - if ( - range0(s0_r0, s0_r1, str0_base_ptr_->size()) && - range1(s1_r0, s1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1; + 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)); - std::copy(str1_base_ptr_->base() + s1_r0, - str1_base_ptr_->base() + s1_r0 + size, - const_cast(base() + s0_r0)); - } + std::copy( + str1_base_ptr_->base() + s1_r0, + str1_base_ptr_->base() + s1_r0 + size, + const_cast(base() + s0_r0)); } return std::numeric_limits::quiet_NaN(); @@ -9419,6 +11252,11 @@ namespace exprtk return expression_node::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -9431,9 +11269,9 @@ namespace exprtk template class conditional_string_node exprtk_final - : public trinary_node , - public string_base_node, - public range_interface + : public trinary_node + , public string_base_node + , public range_interface { public: @@ -9494,55 +11332,48 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (is_true(condition_)) { - assert(condition_ ); - assert(consequent_ ); - assert(alternative_); + consequent_->value(); - std::size_t r0 = 0; - std::size_t r1 = 0; + const range_t& range = str0_range_ptr_->range_ref(); - if (is_true(condition_)) + if (range(r0, r1, str0_base_ptr_->size())) { - consequent_->value(); - - const range_t& range = str0_range_ptr_->range_ref(); + const std::size_t size = (r1 - r0); - if (range(r0, r1, str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; + value_.assign(str0_base_ptr_->base() + r0, size); - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(1); - } + return T(1); } - else - { - alternative_->value(); + } + else + { + alternative_->value(); - const range_t& range = str1_range_ptr_->range_ref(); + const range_t& range = str1_range_ptr_->range_ref(); - if (range(r0, r1, str1_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; + if (range(r0, r1, str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0); - value_.assign(str1_base_ptr_->base() + r0, size); + value_.assign(str1_base_ptr_->base() + r0, size); - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(0); - } + return T(0); } } @@ -9579,6 +11410,15 @@ namespace exprtk return expression_node::e_strcondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() && + alternative_&& alternative_->valid() ; + } + private: bool initialised_; @@ -9596,9 +11436,9 @@ namespace exprtk template class cons_conditional_str_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9640,37 +11480,30 @@ namespace exprtk } initialised_ = str0_base_ptr_ && str0_range_ptr_ ; - - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) + if (is_true(condition_)) { - assert(condition_ ); - assert(consequent_); - - if (is_true(condition_)) - { - consequent_->value(); + consequent_->value(); - const range_t& range = str0_range_ptr_->range_ref(); + const range_t& range = str0_range_ptr_->range_ref(); - std::size_t r0 = 0; - std::size_t r1 = 0; + 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; + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0); - value_.assign(str0_base_ptr_->base() + r0, size); + value_.assign(str0_base_ptr_->base() + r0, size); - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(1); - } + return T(1); } } @@ -9707,6 +11540,14 @@ namespace exprtk return expression_node::e_strccondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() ; + } + private: bool initialised_; @@ -9721,9 +11562,9 @@ namespace exprtk template class str_vararg_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -9759,8 +11600,6 @@ namespace exprtk 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; @@ -9769,7 +11608,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list_size; ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -9779,7 +11618,12 @@ namespace exprtk return; } } + + initialised_ = true; } + + initialised_ &= str_base_ptr_ && str_range_ptr_; + assert(valid()); } inline T value() const exprtk_override @@ -9824,6 +11668,13 @@ namespace exprtk return expression_node::e_stringvararg; } + inline bool valid() const exprtk_override + { + return + initialised_ && + final_node_.first && final_node_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(final_node_ , node_delete_list); @@ -9847,6 +11698,104 @@ namespace exprtk }; #endif + template + class assert_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef string_base_node* str_base_ptr; + typedef assert_check::assert_context assert_context_t; + + assert_node(expression_ptr assert_condition_node, + expression_ptr assert_message_node, + assert_check_ptr assert_check, + assert_context_t context) + : assert_message_str_base_(0) + , assert_check_(assert_check) + , context_(context) + { + construct_branch_pair(assert_condition_node_, assert_condition_node); + construct_branch_pair(assert_message_node_ , assert_message_node ); + + #ifndef exprtk_disable_string_capabilities + if ( + assert_message_node_.first && + details::is_generally_string_node(assert_message_node_.first) + ) + { + assert_message_str_base_ = dynamic_cast(assert_message_node_.first); + } + #endif + + assert(valid()); + } + + inline T value() const exprtk_override + { + if (details::is_true(assert_condition_node_.first->value())) + { + return T(1); + } + + #ifndef exprtk_disable_string_capabilities + if (assert_message_node_.first) + { + assert_message_node_.first->value(); + assert(assert_message_str_base_); + context_.message = assert_message_str_base_->str(); + } + #endif + + assert_check_->handle_assert(context_); + return T(0); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_assert; + } + + inline bool valid() const exprtk_override + { + return ( + assert_check_ && + assert_condition_node_.first && + assert_condition_node_.first->valid() + ) && + ( + (0 == assert_message_node_.first) || + ( + assert_message_node_.first && + assert_message_str_base_ && + assert_message_node_.first->valid() && + details::is_generally_string_node(assert_message_node_.first) + ) + ); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(assert_condition_node_, node_delete_list); + expression_node::ndb_t::collect(assert_message_node_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth + (assert_condition_node_, assert_message_node_); + } + + private: + + branch_t assert_condition_node_; + branch_t assert_message_node_; + str_base_ptr assert_message_str_base_; + assert_check_ptr assert_check_; + mutable assert_context_t context_; + }; + template inline T axn(const T a, const T x) { @@ -10087,10 +12036,6 @@ namespace exprtk inline T value() const exprtk_override { - assert(trinary_node::branch_[0].first); - assert(trinary_node::branch_[1].first); - assert(trinary_node::branch_[2].first); - const T x = trinary_node::branch_[0].first->value(); const T y = trinary_node::branch_[1].first->value(); const T z = trinary_node::branch_[2].first->value(); @@ -10116,11 +12061,6 @@ namespace exprtk inline T value() const exprtk_override { - assert(quaternary_node::branch_[0].first); - assert(quaternary_node::branch_[1].first); - assert(quaternary_node::branch_[2].first); - assert(quaternary_node::branch_[3].first); - const T x = quaternary_node::branch_[0].first->value(); const T y = quaternary_node::branch_[1].first->value(); const T z = quaternary_node::branch_[2].first->value(); @@ -10209,12 +12149,13 @@ namespace exprtk template class Sequence> explicit vararg_node(const Sequence& arg_list) + : initialised_(false) { arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i],arg_list[i]); } @@ -10224,6 +12165,9 @@ namespace exprtk return; } } + + initialised_ = (arg_list_.size() == arg_list.size()); + assert(valid()); } inline T value() const exprtk_override @@ -10236,6 +12180,11 @@ namespace exprtk return expression_node::e_vararg; } + inline bool valid() const exprtk_override + { + return initialised_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -10246,9 +12195,20 @@ namespace exprtk return expression_node::ndb_t::compute_node_depth(arg_list_); } + std::size_t size() const + { + return arg_list_.size(); + } + + expression_ptr operator[](const std::size_t& index) const + { + return arg_list_[index].first; + } + private: std::vector arg_list_; + bool initialised_; }; template @@ -10261,12 +12221,13 @@ namespace exprtk template class Sequence> explicit vararg_varnode(const Sequence& arg_list) + : initialised_(false) { 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])) + if (arg_list[i] && arg_list[i]->valid() && is_variable_node(arg_list[i])) { variable_node* var_node_ptr = static_cast*>(arg_list[i]); arg_list_[i] = (&var_node_ptr->ref()); @@ -10277,14 +12238,14 @@ namespace exprtk return; } } + + initialised_ = (arg_list.size() == arg_list_.size()); + assert(valid()); } inline T value() const exprtk_override { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits::quiet_NaN(); + return VarArgFunction::process(arg_list_); } inline typename expression_node::node_type type() const exprtk_override @@ -10292,9 +12253,15 @@ namespace exprtk return expression_node::e_vararg; } + inline bool valid() const exprtk_override + { + return initialised_; + } + private: std::vector arg_list_; + bool initialised_; }; template @@ -10314,22 +12281,12 @@ namespace exprtk { ivec_ptr_ = dynamic_cast*>(v_.first); } - else - ivec_ptr_ = 0; } inline T value() const exprtk_override { - if (ivec_ptr_) - { - assert(v_.first); - - v_.first->value(); - - return VecFunction::process(ivec_ptr_); - } - else - return std::numeric_limits::quiet_NaN(); + v_.first->value(); + return VecFunction::process(ivec_ptr_); } inline typename expression_node::node_type type() const exprtk_override @@ -10337,6 +12294,11 @@ namespace exprtk return expression_node::e_vecfunc; } + inline bool valid() const exprtk_override + { + return ivec_ptr_ && v_.first && v_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(v_, node_delete_list); @@ -10375,17 +12337,15 @@ namespace exprtk inline T value() const exprtk_override { - if (var_node_ptr_) - { - assert(branch(1)); - - T& result = var_node_ptr_->ref(); + T& result = var_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return var_node_ptr_ && binary_node::valid(); } private: @@ -10411,26 +12371,66 @@ namespace exprtk { vec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) + T& result = vec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_vec_elem_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) { - assert(branch(1)); + vec_node_ptr_ = static_cast*>(branch(0)); + } + + assert(valid()); + } - T& result = vec_node_ptr_->ref(); + inline T value() const exprtk_override + { + T& result = vec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); } private: - vector_elem_node* vec_node_ptr_; + vector_elem_rtc_node* vec_node_ptr_; }; template @@ -10451,27 +12451,66 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) + T& result = rbvec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using expression_node::branch; + + assignment_rebasevec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_rtc_node(branch(0))) { - assert(branch(1)); + rbvec_node_ptr_ = static_cast*>(branch(0)); + } - T& result = rbvec_node_ptr_->ref(); + assert(valid()); + } + inline T value() const exprtk_override + { + T& result = rbvec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - rebasevector_elem_node* rbvec_node_ptr_; + rebasevector_elem_rtc_node* rbvec_node_ptr_; }; template @@ -10492,21 +12531,21 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(branch(1)); - - T& result = rbvec_node_ptr_->ref(); + T& result = rbvec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: @@ -10538,66 +12577,60 @@ namespace exprtk vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(branch(1)); + const T v = branch(1)->value(); - const T v = branch(1)->value(); + T* vec = vds().data(); - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - vec[N] = v; \ + 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 + 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; - } + vec += lud.batch_size; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec++ = v; \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec++ = v; \ + exprtk_fallthrough \ - #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 + #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 1 : *vec++ = v; + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return vec_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -10615,9 +12648,22 @@ namespace exprtk return expression_node::e_vecvalass; } + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (vds().size() <= vec_node_ptr_->vec_holder().base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -10687,74 +12733,71 @@ namespace exprtk } } - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + initialised_ = + vec0_node_ptr_ && + vec1_node_ptr_ && + (size() <= base_size()) && + (vds_.size() <= base_size()) && + binary_node::valid(); - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(1)); + branch(1)->value(); - branch(1)->value(); - - if (src_is_ivec_) - return vec0_node_ptr_->value(); + if (src_is_ivec_) + return vec0_node_ptr_->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + 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; + 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]; \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec0++ = *vec1++; \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : *vec0++ = *vec1++; \ + fall_through \ - #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 + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec0_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return vec0_node_ptr_->value(); } vector_node_ptr vec() exprtk_override @@ -10772,9 +12815,23 @@ namespace exprtk return expression_node::e_vecvecass; } + inline bool valid() const exprtk_override + { + return initialised_; + } + std::size_t size() const exprtk_override { - return vds().size(); + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); } vds_t& vds() exprtk_override @@ -10814,21 +12871,21 @@ namespace exprtk { var_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (var_node_ptr_) - { - assert(branch(1)); + T& v = var_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = var_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + return v; + } - return v; - } - else - return std::numeric_limits::quiet_NaN(); + inline bool valid() const exprtk_override + { + return var_node_ptr_ && binary_node::valid(); } private: @@ -10854,26 +12911,106 @@ namespace exprtk { vec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_vec_elem_op_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) { - assert(branch(1)); + vec_node_ptr_ = static_cast*>(branch(0)); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); + } + + private: + + vector_elem_rtc_node* vec_node_ptr_; + }; + + template + class assignment_vec_celem_op_rtc_node exprtk_final : public binary_node + { + public: - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + typedef expression_node* expression_ptr; + using binary_node::branch; - return v; + assignment_vec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_celem_rtc_node(branch(0))) + { + vec_node_ptr_ = static_cast*>(branch(0)); } - else - return std::numeric_limits::quiet_NaN(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); } private: - vector_elem_node* vec_node_ptr_; + vector_celem_rtc_node* vec_node_ptr_; }; template @@ -10894,21 +13031,21 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(branch(1)); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + return v; + } - return v; - } - else - return std::numeric_limits::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: @@ -10934,26 +13071,106 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_op_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_rebasevec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_rtc_node(branch(0))) { - assert(branch(1)); + rbvec_node_ptr_ = static_cast*>(branch(0)); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); + } - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + private: + + rebasevector_elem_rtc_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_op_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; - return v; + assignment_rebasevec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_rtc_node(branch(0))) + { + rbvec_node_ptr_ = static_cast*>(branch(0)); } - else - return std::numeric_limits::quiet_NaN(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - rebasevector_celem_node* rbvec_node_ptr_; + rebasevector_celem_rtc_node* rbvec_node_ptr_; }; template @@ -10980,66 +13197,60 @@ namespace exprtk vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(branch(1)); - - const T v = branch(1)->value(); + const T v = branch(1)->value(); - T* vec = vds().data(); + T* vec = vds().data(); - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; + 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); \ + 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 + 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; - } + vec += lud.batch_size; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : Operation::assign(*vec++,v); \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : Operation::assign(*vec++,v); \ + fall_through \ - #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 + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return vec_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -11057,9 +13268,22 @@ namespace exprtk return expression_node::e_vecopvalass; } + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (size() <= base_size()) && + binary_node::valid() ; + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11122,81 +13346,76 @@ namespace exprtk if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); - vec1_node_ptr_->vds() = vds(); + vec1_node_ptr_->vds() = vi->vds(); } else vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + initialised_ = + vec0_node_ptr_ && + vec1_node_ptr_ && + (size() <= base_size()) && + binary_node::valid(); - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); + 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; + 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]); \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + 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; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + fall_through \ - #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 + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec0_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return vec0_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -11214,9 +13433,23 @@ namespace exprtk return expression_node::e_vecopvecass; } + inline bool valid() const exprtk_override + { + return initialised_; + } + std::size_t size() const exprtk_override { - return vds().size(); + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); } vds_t& vds() exprtk_override @@ -11242,6 +13475,64 @@ namespace exprtk vds_t vds_; }; + template + struct memory_context_t + { + typedef vector_node* vector_node_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + + memory_context_t() + : temp_(0) + , temp_vec_node_(0) + {} + + void clear() + { + delete temp_vec_node_; + delete temp_; + } + + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + }; + + template + inline memory_context_t make_memory_context(vector_holder& vec_holder, + vec_data_store& vds) + { + memory_context_t result_ctxt; + result_ctxt.temp_ = (vec_holder.rebaseable()) ? + new vector_holder(vec_holder,vds) : + new vector_holder(vds) ; + result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); + return result_ctxt; + } + + template + inline memory_context_t make_memory_context(vector_holder& vec_holder0, + vector_holder& vec_holder1, + vec_data_store& vds) + { + memory_context_t result_ctxt; + + if (!vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vds); + else if (vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vec_holder0,vds); + else if (!vec_holder0.rebaseable() && vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vec_holder1,vds); + else + { + result_ctxt.temp_ = (vec_holder0.base_size() >= vec_holder1.base_size()) ? + new vector_holder(vec_holder0, vds) : + new vector_holder(vec_holder1, vds) ; + } + + result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); + return result_ctxt; + } + template class vec_binop_vecvec_node exprtk_final : public binary_node @@ -11251,8 +13542,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11262,8 +13555,6 @@ namespace exprtk : binary_node(opr, branch0, branch1) , vec0_node_ptr_(0) , vec1_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) , initialised_(false) { bool v0_is_ivec = false; @@ -11304,104 +13595,102 @@ namespace exprtk vector_holder& vec0 = vec0_node_ptr_->vec_holder(); vector_holder& vec1 = vec1_node_ptr_->vec_holder(); - if (v0_is_ivec && (vec0.size() <= vec1.size())) + if (v0_is_ivec && (vec0.base_size() <= vec1.base_size())) + { vds_ = vds_t(vec0_node_ptr_->vds()); - else if (v1_is_ivec && (vec1.size() <= vec0.size())) + } + else if (v1_is_ivec && (vec1.base_size() <= vec0.base_size())) + { vds_ = vds_t(vec1_node_ptr_->vds()); + } else - vds_ = vds_t(std::min(vec0.size(),vec1.size())); + { + vds_ = vds_t(std::min(vec0.base_size(),vec1.base_size())); + } - temp_ = new vector_holder(vds().data(),vds().size()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0, vec1, vds()); - initialised_ = true; + initialised_ = + (size() <= base_size()) && + binary_node::valid(); } - assert(initialised_); + assert(valid()); } ~vec_binop_vecvec_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->value(); - const T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); + 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; + 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]); \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + vec2 += lud.batch_size; + } - int i = 0; + 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; } \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + exprtk_fallthrough \ - #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 + #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) + default: break; + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11409,9 +13698,23 @@ namespace exprtk return expression_node::e_vecvecarith; } + inline bool valid() const exprtk_override + { + return initialised_; + } + std::size_t size() const exprtk_override { - return vds_.size(); + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); } vds_t& vds() exprtk_override @@ -11426,12 +13729,11 @@ namespace exprtk 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_; + vector_node_ptr vec0_node_ptr_; + vector_node_ptr vec1_node_ptr_; + bool initialised_; + vds_t vds_; + memory_context memory_context_; }; template @@ -11443,8 +13745,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11453,8 +13757,6 @@ namespace exprtk expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec0_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool v0_is_ivec = false; @@ -11478,93 +13780,84 @@ namespace exprtk if (v0_is_ivec) vds() = vec0_node_ptr_->vds(); else - vds() = vds_t(vec0_node_ptr_->size()); + vds() = vds_t(vec0_node_ptr_->base_size()); - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~vec_binop_vecval_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (vec0_node_ptr_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - const T v = branch(1)->value(); + branch(0)->value(); + const T v = branch(1)->value(); - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + 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; + 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); \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + fall_through \ - #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 + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11572,9 +13865,22 @@ namespace exprtk return expression_node::e_vecvalarith; } + inline bool valid() const exprtk_override + { + return + vec0_node_ptr_ && + (size() <= base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec0_node_ptr_->size(); + } + + std::size_t base_size() const exprtk_override + { + return vec0_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11590,9 +13896,8 @@ namespace exprtk private: vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; vds_t vds_; + memory_context memory_context_; }; template @@ -11604,8 +13909,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11614,8 +13921,6 @@ namespace exprtk expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec1_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool v1_is_ivec = false; @@ -11639,93 +13944,84 @@ namespace exprtk if (v1_is_ivec) vds() = vec1_node_ptr_->vds(); else - vds() = vds_t(vec1_node_ptr_->size()); + vds() = vds_t(vec1_node_ptr_->base_size()); - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec1_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~vec_binop_valvec_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (vec1_node_ptr_) - { - assert(branch(0)); - assert(branch(1)); - - const T v = branch(0)->value(); - branch(1)->value(); + const T v = branch(0)->value(); + branch(1)->value(); - T* vec0 = vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); + 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; + 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]); \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + fall_through \ - #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 + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11733,9 +14029,23 @@ namespace exprtk return expression_node::e_vecvalarith; } + inline bool valid() const exprtk_override + { + return + vec1_node_ptr_ && + (size() <= base_size()) && + (vds_.size() <= base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec1_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec1_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11751,9 +14061,8 @@ namespace exprtk private: vector_node_ptr vec1_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; vds_t vds_; + memory_context memory_context_; }; template @@ -11765,28 +14074,28 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using expression_node::branch; unary_vector_node(const operator_type& opr, expression_ptr branch0) : unary_node(opr, branch0) , vec0_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool vec0_is_ivec = false; - if (is_vector_node(branch())) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast(branch()); + vec0_node_ptr_ = static_cast(branch(0)); } - else if (is_ivector_node(branch())) + else if (is_ivector_node(branch(0))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(branch()))) + if (0 != (vi = dynamic_cast*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; @@ -11798,91 +14107,84 @@ namespace exprtk if (vec0_is_ivec) vds_ = vec0_node_ptr_->vds(); else - vds_ = vds_t(vec0_node_ptr_->size()); + vds_ = vds_t(vec0_node_ptr_->base_size()); - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~unary_vector_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - assert(branch()); - branch()->value(); - if (vec0_node_ptr_) - { - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + 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; + 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]); \ + 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 + 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; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + exprtk_fallthrough \ - #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 + #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) + default: break; + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11890,9 +14192,19 @@ namespace exprtk return expression_node::e_vecunaryop; } + inline bool valid() const exprtk_override + { + return vec0_node_ptr_ && unary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec0_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec0_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11907,10 +14219,9 @@ namespace exprtk private: - vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; + vector_node_ptr vec0_node_ptr_; + vds_t vds_; + memory_context memory_context_; }; template @@ -11923,8 +14234,10 @@ namespace exprtk typedef expression_node * expression_ptr; typedef vector_interface* vec_interface_ptr; typedef vector_node * vector_node_ptr; - typedef vector_holder * vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; typedef std::pair branch_t; conditional_vector_node(expression_ptr condition, @@ -11934,7 +14247,7 @@ namespace exprtk , alternative_node_ptr_(0) , temp_vec_node_ (0) , temp_ (0) - , vec_size_ (0) + , result_vec_size_ (0) , initialised_ (false) { construct_branch_pair(condition_ , condition ); @@ -11963,67 +14276,62 @@ namespace exprtk if (consequent_node_ptr_ && alternative_node_ptr_) { - vec_size_ = std::min(consequent_node_ptr_ ->vds().size(), - alternative_node_ptr_->vds().size()); + const std::size_t vec_size = + std::max(consequent_node_ptr_ ->vec_holder().base_size(), + alternative_node_ptr_->vec_holder().base_size()); - vds_ = vds_t(vec_size_); - temp_ = new vector_holder(vds_); - temp_vec_node_ = new vector_node (vds(),temp_); + vds_ = vds_t(vec_size); + memory_context_ = make_memory_context( + consequent_node_ptr_ ->vec_holder(), + alternative_node_ptr_->vec_holder(), + vds()); - initialised_ = true; + initialised_ = (vec_size > 0); } - assert(initialised_ && (vec_size_ > 0)); + assert(initialised_); } ~conditional_vector_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } 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(); - } + T result = T(0); + T* source_vector = 0; + T* result_vector = vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) - { - result_vector[i] = source_vector[i]; - } + if (is_true(condition_)) + { + result = consequent_.first->value(); + source_vector = consequent_node_ptr_->vds().data(); + result_vec_size_ = consequent_node_ptr_->size(); + } + else + { + result = alternative_.first->value(); + source_vector = alternative_node_ptr_->vds().data(); + result_vec_size_ = alternative_node_ptr_->size(); + } - return result; + for (std::size_t i = 0; i < result_vec_size_; ++i) + { + result_vector[i] = source_vector[i]; } - return std::numeric_limits::quiet_NaN(); + return result; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -12031,9 +14339,26 @@ namespace exprtk return expression_node::e_vecondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ .first && condition_ .first->valid() && + consequent_ .first && consequent_ .first->valid() && + alternative_.first && alternative_.first->valid() && + size() <= base_size(); + } + std::size_t size() const exprtk_override { - return vec_size_; + return result_vec_size_; + } + + std::size_t base_size() const exprtk_override + { + return std::min( + consequent_node_ptr_ ->vec_holder().base_size(), + alternative_node_ptr_->vec_holder().base_size()); } vds_t& vds() exprtk_override @@ -12061,16 +14386,17 @@ namespace exprtk 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_; + 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_; + mutable std::size_t result_vec_size_; + bool initialised_; + memory_context memory_context_; }; template @@ -12085,13 +14411,12 @@ namespace exprtk expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) - {} + { + assert(binary_node::valid()); + } inline T value() const exprtk_override { - assert(branch(0)); - assert(branch(1)); - return ( std::not_equal_to() (T(0),branch(0)->value()) && @@ -12113,13 +14438,12 @@ namespace exprtk expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) - {} + { + assert(binary_node::valid()); + } inline T value() const exprtk_override { - assert(branch(0)); - assert(branch(1)); - return ( std::not_equal_to() (T(0),branch(0)->value()) || @@ -12134,7 +14458,7 @@ namespace exprtk { public: - // Function of N paramters. + // Function of N parameters. typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef IFunction ifunction; @@ -12142,6 +14466,7 @@ namespace exprtk explicit function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast(0)) , parameter_count_(func->param_count) + , initialised_(false) {} template @@ -12152,19 +14477,24 @@ namespace exprtk #pragma warning(push) #pragma warning(disable: 4127) #endif + if (N != NumBranches) + { return false; - else + } + + for (std::size_t i = 0; i < NumBranches; ++i) { - 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; + if (b[i] && b[i]->valid()) + branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); + else + return false; } + + initialised_ = function_; + assert(valid()); + return initialised_; + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -12182,14 +14512,11 @@ namespace exprtk #pragma warning(push) #pragma warning(disable: 4127) #endif - if ((0 == function_) || (0 == N)) - return std::numeric_limits::quiet_NaN(); - else - { - T v[N]; - evaluate_branches::execute(v,branch_); - return invoke::execute(*function_,v); - } + + T v[N]; + evaluate_branches::execute(v,branch_); + return invoke::execute(*function_,v); + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -12200,9 +14527,14 @@ namespace exprtk return expression_node::e_function; } + inline bool valid() const exprtk_override + { + return initialised_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -12222,6 +14554,20 @@ namespace exprtk } }; + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[6], const branch_t (&b)[6]) + { + 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(); + v[5] = b[5].first->value(); + } + }; + template struct evaluate_branches { @@ -12425,6 +14771,7 @@ namespace exprtk ifunction* function_; std::size_t parameter_count_; branch_t branch_[N]; + bool initialised_; }; template @@ -12437,7 +14784,9 @@ namespace exprtk explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast(0)) - {} + { + assert(valid()); + } inline bool operator <(const function_N_node& fn) const { @@ -12446,10 +14795,7 @@ namespace exprtk inline T value() const exprtk_override { - if (function_) - return (*function_)(); - else - return std::numeric_limits::quiet_NaN(); + return (*function_)(); } inline typename expression_node::node_type type() const exprtk_override @@ -12457,6 +14803,11 @@ namespace exprtk return expression_node::e_function; } + inline bool valid() const exprtk_override + { + return function_; + } + private: ifunction* function_; @@ -12475,6 +14826,7 @@ namespace exprtk , arg_list_(arg_list) { value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); + assert(valid()); } inline bool operator <(const vararg_function_node& fn) const @@ -12484,13 +14836,8 @@ namespace exprtk inline T value() const exprtk_override { - if (function_) - { - populate_value_list(); - return (*function_)(value_list_); - } - else - return std::numeric_limits::quiet_NaN(); + populate_value_list(); + return (*function_)(value_list_); } inline typename expression_node::node_type type() const exprtk_override @@ -12498,6 +14845,11 @@ namespace exprtk return expression_node::e_vafunction; } + inline bool valid() const exprtk_override + { + return function_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { for (std::size_t i = 0; i < arg_list_.size(); ++i) @@ -12545,7 +14897,8 @@ namespace exprtk typedef typename range_interface::range_t range_t; typedef std::pair branch_t; - typedef std::pair void_t; + typedef vector_holder* vh_t; + typedef vector_view* vecview_t; typedef std::vector tmp_vs_t; typedef std::vector typestore_list_t; @@ -12557,7 +14910,18 @@ namespace exprtk , arg_list_(arg_list) {} - virtual ~generic_function_node() {} + virtual ~generic_function_node() + { + for (std::size_t i = 0; i < vv_list_.size(); ++i) + { + vecview_t& vv = vv_list_[i]; + if (vv && typestore_list_[i].vec_data) + { + vv->remove_ref(&typestore_list_[i].vec_data); + typestore_list_[i].vec_data = 0; + } + } + } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { @@ -12571,10 +14935,11 @@ namespace exprtk virtual bool init_branches() { - expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); - typestore_list_ .resize(arg_list_.size(),type_store_t() ); - range_list_ .resize(arg_list_.size(),range_data_type_t()); - branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast(0),false)); + expr_as_vec1_store_.resize(arg_list_.size(), T(0) ); + typestore_list_ .resize(arg_list_.size(), type_store_t() ); + range_list_ .resize(arg_list_.size(), range_data_type_t()); + branch_ .resize(arg_list_.size(), branch_t(reinterpret_cast(0),false)); + vv_list_ .resize(arg_list_.size(), vecview_t(0)); for (std::size_t i = 0; i < arg_list_.size(); ++i) { @@ -12592,7 +14957,15 @@ namespace exprtk 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); + + if ( + vi->vec()->vec_holder().rebaseable() && + vi->vec()->vec_holder().rebaseable_instance() + ) + { + vv_list_[i] = vi->vec()->vec_holder().rebaseable_instance(); + vv_list_[i]->set_ref(&ts.vec_data); + } } #ifndef exprtk_disable_string_capabilities else if (is_generally_string_node(arg_list_[i])) @@ -12628,7 +15001,10 @@ namespace exprtk range_list_[i].range = reinterpret_cast(0); } else + { range_list_[i].range = &(ri->range_ref()); + range_param_list_.push_back(i); + } } #endif else if (is_variable_node(arg_list_[i])) @@ -12662,14 +15038,11 @@ namespace exprtk inline T value() const exprtk_override { - if (function_) + if (populate_value_list()) { - if (populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; + typedef typename GenericFunction::parameter_list_t parameter_list_t; - return (*function_)(parameter_list_t(typestore_list_)); - } + return (*function_)(parameter_list_t(typestore_list_)); } return std::numeric_limits::quiet_NaN(); @@ -12680,6 +15053,11 @@ namespace exprtk return expression_node::e_genfunction; } + inline bool valid() const exprtk_override + { + return function_; + } + protected: inline virtual bool populate_value_list() const @@ -12689,30 +15067,40 @@ namespace exprtk expr_as_vec1_store_[i] = branch_[i].first->value(); } - for (std::size_t i = 0; i < branch_.size(); ++i) + if (!range_param_list_.empty()) { - range_data_type_t& rdt = range_list_[i]; + assert(range_param_list_.size() <= branch_.size()); - if (rdt.range) + for (std::size_t i = 0; i < range_param_list_.size(); ++i) { + const std::size_t index = range_param_list_[i]; + range_data_type_t& rdt = range_list_[index]; + const range_t& rp = (*rdt.range); std::size_t r0 = 0; std::size_t r1 = 0; - if (rp(r0, r1, rdt.size)) - { - type_store_t& ts = typestore_list_[i]; + const std::size_t data_size = + #ifndef exprtk_disable_string_capabilities + rdt.str_node ? rdt.str_node->size() : rdt.size; + #else + rdt.size; + #endif - ts.size = rp.cache_size(); - #ifndef exprtk_disable_string_capabilities - if (ts.type == type_store_t::e_string) - ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; - else - #endif - ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + if (!rp(r0, r1, data_size)) + { + return false; } + + type_store_t& ts = typestore_list_[index]; + + ts.size = rp.cache_size(); + #ifndef exprtk_disable_string_capabilities + if (ts.type == type_store_t::e_string) + ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; else - return false; + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); } } @@ -12725,16 +15113,18 @@ namespace exprtk private: std::vector arg_list_; - std::vector branch_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; + std::vector branch_; + std::vector vv_list_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + std::vector range_param_list_; }; #ifndef exprtk_disable_string_capabilities template - class string_function_node : public generic_function_node, - public string_base_node, - public range_interface + class string_function_node : public generic_function_node + , public string_base_node + , public range_interface { public: @@ -12749,6 +15139,7 @@ namespace exprtk range_.n1_c = std::make_pair(true,0); range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; + assert(valid()); } inline bool operator <(const string_function_node& fn) const @@ -12758,23 +15149,21 @@ namespace exprtk inline T value() const exprtk_override { - if (gen_function_t::function_) + if (gen_function_t::populate_value_list()) { - if (gen_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; + 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_) - ); + 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; + range_.n1_c.second = ret_string_.size(); + range_.cache.second = range_.n1_c.second; - return result; - } + return result; } return std::numeric_limits::quiet_NaN(); @@ -12785,6 +15174,11 @@ namespace exprtk return expression_node::e_strfunction; } + inline bool valid() const exprtk_override + { + return gen_function_t::function_; + } + std::string str() const exprtk_override { return ret_string_; @@ -12834,18 +15228,18 @@ namespace exprtk inline T value() const exprtk_override { - if (gen_function_t::function_) + assert(gen_function_t::valid()); + + if (gen_function_t::populate_value_list()) { - if (gen_function_t::populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; + 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 + (*gen_function_t::function_) + ( + param_seq_index_, + parameter_list_t(gen_function_t::typestore_list_) + ); } return std::numeric_limits::quiet_NaN(); @@ -12879,24 +15273,22 @@ namespace exprtk inline T value() const exprtk_override { - if (str_function_t::function_) + if (str_function_t::populate_value_list()) { - if (str_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; + 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_) - ); + 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; + str_function_t::range_.n1_c.second = str_function_t::ret_string_.size(); + str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; - return result; - } + return result; } return std::numeric_limits::quiet_NaN(); @@ -12913,15 +15305,15 @@ namespace exprtk }; #endif - class return_exception - {}; + class return_exception {}; template class null_igenfunc { public: - virtual ~null_igenfunc() {} + virtual ~null_igenfunc() + {} typedef type_store generic_type; typedef typename generic_type::parameter_list parameter_list_t; @@ -12947,14 +15339,13 @@ namespace exprtk results_context_t& rc) : gen_function_t (arg_list) , results_context_(&rc) - {} + { + assert(valid()); + } inline T value() const exprtk_override { - if ( - (0 != results_context_) && - gen_function_t::populate_value_list() - ) + if (gen_function_t::populate_value_list()) { typedef typename type_store::parameter_list parameter_list_t; @@ -12972,6 +15363,11 @@ namespace exprtk return expression_node::e_return; } + inline bool valid() const exprtk_override + { + return results_context_; + } + private: results_context_t* results_context_; @@ -12991,12 +15387,11 @@ namespace exprtk , return_invoked_ (false) { construct_branch_pair(body_, body); + assert(valid()); } inline T value() const exprtk_override { - assert(body_.first); - try { return_invoked_ = false; @@ -13007,6 +15402,7 @@ namespace exprtk catch(const return_exception&) { return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); } } @@ -13016,6 +15412,11 @@ namespace exprtk return expression_node::e_retenv; } + inline bool valid() const exprtk_override + { + return results_context_ && body_.first; + } + inline bool* retinvk_ptr() { return &return_invoked_; @@ -13400,7 +15801,7 @@ namespace exprtk } template - struct vararg_add_op : public opr_base + struct vararg_add_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13423,7 +15824,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - result += value(arg_list[i]); + result += value(arg_list[i]); } return result; @@ -13467,7 +15868,7 @@ namespace exprtk }; template - struct vararg_mul_op : public opr_base + struct vararg_mul_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13534,7 +15935,7 @@ namespace exprtk }; template - struct vararg_avg_op : public opr_base + struct vararg_avg_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13590,7 +15991,7 @@ namespace exprtk }; template - struct vararg_min_op : public opr_base + struct vararg_min_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13661,7 +16062,7 @@ namespace exprtk }; template - struct vararg_max_op : public opr_base + struct vararg_max_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13732,7 +16133,7 @@ namespace exprtk }; template - struct vararg_mand_op : public opr_base + struct vararg_mand_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13812,7 +16213,7 @@ namespace exprtk }; template - struct vararg_mor_op : public opr_base + struct vararg_mor_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13892,7 +16293,7 @@ namespace exprtk }; template - struct vararg_multi_op : public opr_base + struct vararg_multi_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13913,14 +16314,13 @@ namespace exprtk 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()); - } + { + for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) + { + value(arg_list[i]); + } + return value(arg_list.back()); + } } } @@ -14009,7 +16409,7 @@ namespace exprtk 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(); + const std::size_t vec_size = v->size(); loop_unroll::details lud(vec_size); @@ -14018,24 +16418,24 @@ namespace exprtk T result = T(0); int i = 0; - exprtk_disable_fallthrough_begin switch (vec_size) { - #define case_stmt(N) \ - case N : result += vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : result += vec[i++]; \ + fall_through \ #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) + case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) + case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) + case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) + case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) + case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) + case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) + #endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) + case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) + case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef case_stmt @@ -14070,24 +16470,23 @@ namespace exprtk int i = 0; - exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : r[0] += vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : r[0] += vec[i++]; \ + fall_through \ #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) + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -14110,7 +16509,7 @@ namespace exprtk 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(); + const std::size_t vec_size = v->vec()->size(); loop_unroll::details lud(vec_size); @@ -14119,24 +16518,23 @@ namespace exprtk T result = T(1); int i = 0; - exprtk_disable_fallthrough_begin switch (vec_size) { - #define case_stmt(N) \ - case N : result *= vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : result *= vec[i++]; \ + fall_through \ #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) + case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) + case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) + case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) + case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) + case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) + case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) #endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) + case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) + case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef case_stmt @@ -14171,33 +16569,32 @@ namespace exprtk int i = 0; - exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : r[0] *= vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : r[0] *= vec[i++]; \ + fall_through \ #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) + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) } - 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]) + * (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 ; } @@ -14210,7 +16607,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { - const T vec_size = T(v->vec()->vds().size()); + const T vec_size = T(v->vec()->size()); return vec_add_op::process(v) / vec_size; } }; @@ -14223,7 +16620,7 @@ namespace exprtk 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(); + const std::size_t vec_size = v->vec()->size(); T result = vec[0]; @@ -14247,7 +16644,7 @@ namespace exprtk 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(); + const std::size_t vec_size = v->vec()->size(); T result = vec[0]; @@ -14268,7 +16665,8 @@ namespace exprtk { public: - virtual ~vov_base_node() {} + virtual ~vov_base_node() + {} inline virtual operator_type operation() const { @@ -14285,7 +16683,8 @@ namespace exprtk { public: - virtual ~cov_base_node() {} + virtual ~cov_base_node() + {} inline virtual operator_type operation() const { @@ -14302,7 +16701,8 @@ namespace exprtk { public: - virtual ~voc_base_node() {} + virtual ~voc_base_node() + {} inline virtual operator_type operation() const { @@ -14319,7 +16719,8 @@ namespace exprtk { public: - virtual ~vob_base_node() {} + virtual ~vob_base_node() + {} virtual const T& v() const = 0; }; @@ -14329,7 +16730,8 @@ namespace exprtk { public: - virtual ~bov_base_node() {} + virtual ~bov_base_node() + {} virtual const T& v() const = 0; }; @@ -14339,7 +16741,8 @@ namespace exprtk { public: - virtual ~cob_base_node() {} + virtual ~cob_base_node() + {} inline virtual operator_type operation() const { @@ -14358,7 +16761,8 @@ namespace exprtk { public: - virtual ~boc_base_node() {} + virtual ~boc_base_node() + {} inline virtual operator_type operation() const { @@ -14377,7 +16781,8 @@ namespace exprtk { public: - virtual ~uv_base_node() {} + virtual ~uv_base_node() + {} inline virtual operator_type operation() const { @@ -14392,7 +16797,8 @@ namespace exprtk { public: - virtual ~sos_base_node() {} + virtual ~sos_base_node() + {} inline virtual operator_type operation() const { @@ -14405,7 +16811,8 @@ namespace exprtk { public: - virtual ~sosos_base_node() {} + virtual ~sosos_base_node() + {} inline virtual operator_type operation() const { @@ -14418,7 +16825,8 @@ namespace exprtk { public: - virtual ~T0oT1oT2_base_node() {} + virtual ~T0oT1oT2_base_node() + {} virtual std::string type_id() const = 0; }; @@ -14428,7 +16836,8 @@ namespace exprtk { public: - virtual ~T0oT1oT2oT3_base_node() {} + virtual ~T0oT1oT2oT3_base_node() + {} virtual std::string type_id() const = 0; }; @@ -14564,6 +16973,11 @@ namespace exprtk return Operation::type(); } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline operator_type operation() { return Operation::operation(); @@ -15186,7 +17600,8 @@ namespace exprtk { public: - virtual ~sf3ext_type_node() {} + virtual ~sf3ext_type_node() + {} virtual T0 t0() const = 0; @@ -15644,16 +18059,16 @@ namespace exprtk typedef std::pair branch_t; typedef Operation operation_t; - // variable op constant node + // variable op binary node explicit vob_node(const T& var, const expression_ptr branch) : v_(var) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(v_,branch_.first->value()); } @@ -15662,6 +18077,11 @@ namespace exprtk return v_; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15669,7 +18089,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15695,16 +18115,16 @@ namespace exprtk typedef std::pair branch_t; typedef Operation operation_t; - // variable op constant node + // binary node op variable node explicit bov_node(const expression_ptr branch, const T& var) : v_(var) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),v_); } @@ -15713,6 +18133,11 @@ namespace exprtk return v_; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15720,7 +18145,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15746,16 +18171,16 @@ namespace exprtk typedef std::pair branch_t; typedef Operation operation_t; - // variable op constant node + // constant op variable node explicit cob_node(const T const_var, const expression_ptr branch) : c_(const_var) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(c_,branch_.first->value()); } @@ -15774,6 +18199,11 @@ namespace exprtk (*const_cast(&c_)) = new_c; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15787,7 +18217,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15813,16 +18243,16 @@ namespace exprtk typedef std::pair branch_t; typedef Operation operation_t; - // variable op constant node + // binary node op constant node explicit boc_node(const expression_ptr branch, const T const_var) : c_(const_var) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),c_); } @@ -15841,6 +18271,11 @@ namespace exprtk (*const_cast(&c_)) = new_c; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15854,7 +18289,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -16013,7 +18448,13 @@ namespace exprtk std::size_t r1 = 0; if (rp1_(r0, r1, s1_.size())) - return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); + { + return Operation::process + ( + s0_, + s1_.substr(r0, (r1 - r0) + 1) + ); + } else return T(0); } @@ -16085,10 +18526,11 @@ namespace exprtk 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) - ); + 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); @@ -16149,6 +18591,7 @@ namespace exprtk , str1_base_ptr_ (0) , str0_range_ptr_(0) , str1_range_ptr_(0) + , initialised_ (false) { if (is_generally_string_node(branch(0))) { @@ -16179,39 +18622,40 @@ namespace exprtk str1_range_ptr_ = &(range->range_ref()); } + + initialised_ = + str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_; + + assert(valid()); } inline T value() const exprtk_override { - if ( - str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ - ) - { - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->value(); - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - return Operation::process( - str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), - str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) - ); - } + 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)), + str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0)) + ); } return std::numeric_limits::quiet_NaN(); @@ -16222,6 +18666,11 @@ namespace exprtk return Operation::type(); } + inline bool valid() const exprtk_override + { + return initialised_; + } + private: str_sogens_node(const str_sogens_node&) exprtk_delete; @@ -16231,6 +18680,7 @@ namespace exprtk str_base_ptr str1_base_ptr_; range_ptr str0_range_ptr_; range_ptr str1_range_ptr_; + bool initialised_; }; template @@ -16242,7 +18692,7 @@ namespace exprtk typedef Operation operation_t; typedef sosos_node node_type; - // variable op variable node + // string op string op string node explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) : s0_(p0) , s1_(p1) @@ -16334,11 +18784,11 @@ namespace exprtk explicit bipow_node(expression_ptr branch) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return PowOp::result(branch_.first->value()); } @@ -16347,6 +18797,11 @@ namespace exprtk return expression_node::e_ipow; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -16396,7 +18851,7 @@ namespace exprtk }; template - class bipowninv_node exprtk_final : public expression_node + class bipowinv_node exprtk_final : public expression_node { public: @@ -16404,14 +18859,14 @@ namespace exprtk typedef std::pair branch_t; typedef PowOp operation_t; - explicit bipowninv_node(expression_ptr branch) + explicit bipowinv_node(expression_ptr branch) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return (T(1) / PowOp::result(branch_.first->value())); } @@ -16420,9 +18875,14 @@ namespace exprtk return expression_node::e_ipowinv; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -16432,8 +18892,8 @@ namespace exprtk private: - bipowninv_node(const bipowninv_node&) exprtk_delete; - bipowninv_node& operator=(const bipowninv_node&) exprtk_delete; + bipowinv_node(const bipowinv_node&) exprtk_delete; + bipowinv_node& operator=(const bipowinv_node&) exprtk_delete; branch_t branch_; }; @@ -16577,6 +19037,46 @@ namespace exprtk return false; } + template + inline bool is_loop_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case expression_node::e_for : + case expression_node::e_repeat : + case expression_node::e_while : return true; + default : return false; + } + } + + return false; + } + + template + inline bool is_block_node(const expression_node* node) + { + if (node) + { + if (is_loop_node(node)) + { + return true; + } + + switch (node->type()) + { + case expression_node::e_conditional : + case expression_node::e_mswitch : + case expression_node::e_switch : + case expression_node::e_vararg : return true; + default : return false; + } + } + + return false; + } + class node_allocator { public: @@ -17117,7 +19617,8 @@ namespace exprtk : param_count(pc) {} - virtual ~ifunction() {} + virtual ~ifunction() + {} #define empty_method_body(N) \ { \ @@ -17208,7 +19709,8 @@ namespace exprtk { public: - virtual ~ivararg_function() {} + virtual ~ivararg_function() + {} inline virtual T operator() (const std::vector&) { @@ -17233,12 +19735,13 @@ namespace exprtk typedef type_store generic_type; typedef typename generic_type::parameter_list parameter_list_t; - igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + explicit igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) : parameter_sequence(param_seq) , rtrn_type(rtr_type) {} - virtual ~igeneric_function() {} + virtual ~igeneric_function() + {} #define igeneric_function_empty_body(N) \ { \ @@ -17262,6 +19765,8 @@ namespace exprtk inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) igeneric_function_empty_body(4) + #undef igeneric_function_empty_body + std::string parameter_sequence; return_type rtrn_type; }; @@ -17337,52 +19842,52 @@ namespace exprtk protected: - struct freefunc00 : public exprtk::ifunction + struct freefunc00 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} - inline T operator() () + inline T operator() () exprtk_override { return f(); } ff00_functor f; }; - struct freefunc01 : public exprtk::ifunction + struct freefunc01 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} - inline T operator() (const T& v0) + inline T operator() (const T& v0) exprtk_override { return f(v0); } ff01_functor f; }; - struct freefunc02 : public exprtk::ifunction + struct freefunc02 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} - inline T operator() (const T& v0, const T& v1) + inline T operator() (const T& v0, const T& v1) exprtk_override { return f(v0, v1); } ff02_functor f; }; - struct freefunc03 : public exprtk::ifunction + struct freefunc03 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2) + inline T operator() (const T& v0, const T& v1, const T& v2) exprtk_override { return f(v0, v1, v2); } ff03_functor f; }; - struct freefunc04 : public exprtk::ifunction + struct freefunc04 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) exprtk_override { return f(v0, v1, v2, v3); } ff04_functor f; }; @@ -17392,120 +19897,120 @@ namespace exprtk using exprtk::ifunction::operator(); explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) exprtk_override { return f(v0, v1, v2, v3, v4); } ff05_functor f; }; - struct freefunc06 : public exprtk::ifunction + struct freefunc06 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) exprtk_override { return f(v0, v1, v2, v3, v4, v5); } ff06_functor f; }; - struct freefunc07 : public exprtk::ifunction + struct freefunc07 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6) + const T& v5, const T& v6) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6); } ff07_functor f; }; - struct freefunc08 : public exprtk::ifunction + struct freefunc08 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7) + const T& v5, const T& v6, const T& v7) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7); } ff08_functor f; }; - struct freefunc09 : public exprtk::ifunction + struct freefunc09 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8) + const T& v5, const T& v6, const T& v7, const T& v8) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } ff09_functor f; }; - struct freefunc10 : public exprtk::ifunction + struct freefunc10 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } ff10_functor f; }; - struct freefunc11 : public exprtk::ifunction + struct freefunc11 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } ff11_functor f; }; - struct freefunc12 : public exprtk::ifunction + struct freefunc12 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11) + const T& v10, const T& v11) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } ff12_functor f; }; - struct freefunc13 : public exprtk::ifunction + struct freefunc13 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12) + const T& v10, const T& v11, const T& v12) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } ff13_functor f; }; - struct freefunc14 : public exprtk::ifunction + struct freefunc14 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13) + const T& v10, const T& v11, const T& v12, const T& v13) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } ff14_functor f; }; - struct freefunc15 : public exprtk::ifunction + struct freefunc15 exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } ff15_functor f; }; @@ -17765,7 +20270,7 @@ namespace exprtk { static inline bool test(const variable_node_t* p, const void* ptr) { - exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); + exprtk_debug(("ptr_match::test() - %p <--> %p\n", reinterpret_cast(&(p->ref())), ptr)); return (&(p->ref()) == ptr); } }; @@ -18029,7 +20534,7 @@ namespace exprtk public: - symbol_table(const symtab_mutability_type mutability = e_mutable) + explicit symbol_table(const symtab_mutability_type mutability = e_mutable) : control_block_(control_block::create()) { control_block_->set_mutability(mutability); @@ -18508,6 +21013,34 @@ namespace exprtk return false; } + #define exprtk_define_reserved_function(NN) \ + inline bool add_reserved_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name,false)) \ + { return false; } \ + if (symbol_exists(function_name,false)) \ + { return false; } \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_reserved_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_reserved_function(00) exprtk_define_reserved_function(01) + exprtk_define_reserved_function(02) exprtk_define_reserved_function(03) + exprtk_define_reserved_function(04) exprtk_define_reserved_function(05) + exprtk_define_reserved_function(06) exprtk_define_reserved_function(07) + exprtk_define_reserved_function(08) exprtk_define_reserved_function(09) + exprtk_define_reserved_function(10) exprtk_define_reserved_function(11) + exprtk_define_reserved_function(12) exprtk_define_reserved_function(13) + exprtk_define_reserved_function(14) exprtk_define_reserved_function(15) + + #undef exprtk_define_reserved_function + template inline bool add_vector(const std::string& vector_name, T (&v)[N]) { @@ -18682,12 +21215,48 @@ namespace exprtk template class Sequence> - inline std::size_t get_vector_list(Sequence& vlist) const + inline std::size_t get_vector_list(Sequence& vec_list) const { if (!valid()) return 0; else - return local_data().vector_store.get_list(vlist); + return local_data().vector_store.get_list(vec_list); + } + + template class Sequence> + inline std::size_t get_function_list(Sequence& function_list) const + { + if (!valid()) + return 0; + + std::vector function_names; + std::size_t count = 0; + + count += local_data().function_store .get_list(function_names); + count += local_data().vararg_function_store .get_list(function_names); + count += local_data().generic_function_store .get_list(function_names); + count += local_data().string_function_store .get_list(function_names); + count += local_data().overload_function_store.get_list(function_names); + + std::set function_set; + + for (std::size_t i = 0; i < function_names.size(); ++i) + { + function_set.insert(function_names[i]); + } + + std::copy(function_set.begin(), function_set.end(), + std::back_inserter(function_list)); + + return count; + } + + inline std::vector get_function_list() const + { + std::vector result; + get_function_list(result); + return result; } inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const @@ -18878,6 +21447,38 @@ namespace exprtk } } + inline void load_variables_from(const symbol_table& st) + { + std::vector name_list; + + st.local_data().variable_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + T& variable = st.get_variable(name_list[i])->ref(); + add_variable(name_list[i], variable); + } + } + } + + inline void load_vectors_from(const symbol_table& st) + { + std::vector name_list; + + st.local_data().vector_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + vector_holder_t& vecholder = *st.get_vector(name_list[i]); + add_vector(name_list[i], vecholder.data(), vecholder.size()); + } + } + } + private: inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const @@ -18973,6 +21574,21 @@ namespace exprtk e_string }; + static std::string to_str(data_type dt) + { + switch(dt) + { + case e_unknown : return "e_unknown "; + case e_expr : return "e_expr" ; + case e_vecholder : return "e_vecholder"; + case e_data : return "e_data" ; + case e_vecdata : return "e_vecdata" ; + case e_string : return "e_string" ; + } + + return ""; + } + struct data_pack { data_pack() @@ -19178,17 +21794,18 @@ namespace exprtk return details::is_true(value()); } - inline void register_symbol_table(symbol_table& st) + inline bool register_symbol_table(symbol_table& st) { for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) { - if (&st == &symbol_table_list_[i]) + if (st == symbol_table_list_[i]) { - return; + return false; } } symbol_table_list_.push_back(st); + return true; } inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const @@ -19201,6 +21818,11 @@ namespace exprtk return symbol_table_list_[index]; } + std::size_t num_symbol_tables() const + { + return symbol_table_list_.size(); + } + typedef results_context results_context_t; inline const results_context_t& results() const @@ -19330,6 +21952,8 @@ namespace exprtk friend class parser; friend class expression_helper; friend class function_compositor; + template + friend bool is_valid(const expression& expr); }; // class expression template @@ -19337,55 +21961,165 @@ namespace exprtk { public: - static inline bool is_constant(const expression& expr) + enum node_types + { + e_literal, + e_variable, + e_string, + e_unary, + e_binary, + e_function, + e_vararg, + e_null, + e_assert, + e_sf3ext, + e_sf4ext + }; + + static inline bool is_literal(const expression& expr) { - return details::is_constant_node(expr.control_block_->expr); + return expr.control_block_ && details::is_literal_node(expr.control_block_->expr); } static inline bool is_variable(const expression& expr) { - return details::is_variable_node(expr.control_block_->expr); + return expr.control_block_ && details::is_variable_node(expr.control_block_->expr); + } + + static inline bool is_string(const expression& expr) + { + return expr.control_block_ && details::is_generally_string_node(expr.control_block_->expr); } static inline bool is_unary(const expression& expr) { - return details::is_unary_node(expr.control_block_->expr); + return expr.control_block_ && details::is_unary_node(expr.control_block_->expr); } static inline bool is_binary(const expression& expr) { - return details::is_binary_node(expr.control_block_->expr); + return expr.control_block_ && details::is_binary_node(expr.control_block_->expr); } static inline bool is_function(const expression& expr) { - return details::is_function(expr.control_block_->expr); + return expr.control_block_ && details::is_function(expr.control_block_->expr); + } + + static inline bool is_vararg(const expression& expr) + { + return expr.control_block_ && details::is_vararg_node(expr.control_block_->expr); } static inline bool is_null(const expression& expr) { - return details::is_null_node(expr.control_block_->expr); + return expr.control_block_ && details::is_null_node(expr.control_block_->expr); + } + + static inline bool is_assert(const expression& expr) + { + return expr.control_block_ && details::is_assert_node(expr.control_block_->expr); + } + + static inline bool is_sf3ext(const expression& expr) + { + return expr.control_block_ && details::is_sf3ext_node(expr.control_block_->expr); + } + + static inline bool is_sf4ext(const expression& expr) + { + return expr.control_block_ && details::is_sf4ext_node(expr.control_block_->expr); + } + + static inline bool is_type(const expression& expr, const node_types node_type) + { + if (0 == expr.control_block_) + { + return false; + } + + switch (node_type) + { + case e_literal : return is_literal_node(expr); + case e_variable : return is_variable (expr); + case e_string : return is_string (expr); + case e_unary : return is_unary (expr); + case e_binary : return is_binary (expr); + case e_function : return is_function (expr); + case e_null : return is_null (expr); + case e_assert : return is_assert (expr); + case e_sf3ext : return is_sf3ext (expr); + case e_sf4ext : return is_sf4ext (expr); + }; + + return false; + } + + static inline bool match_type_sequence(const expression& expr, const std::vector& type_seq) + { + if ((0 == expr.control_block_) || !is_vararg(expr)) + { + return false; + } + + typedef details::vararg_node > mo_vararg_t; + + mo_vararg_t* vnode = dynamic_cast(expr.control_block_->expr); + + if ( + (0 == vnode) || + type_seq.empty() || + (vnode->size() < type_seq.size()) + ) + { + return false; + } + + for (std::size_t i = 0; i < type_seq.size(); ++i) + { + assert((*vnode)[i]); + + switch(type_seq[i]) + { + case e_literal : { if (details::is_literal_node ((*vnode)[i])) continue; } break; + case e_variable : { if (details::is_variable_node ((*vnode)[i])) continue; } break; + case e_string : { if (details::is_generally_string_node((*vnode)[i])) continue; } break; + case e_unary : { if (details::is_unary_node ((*vnode)[i])) continue; } break; + case e_binary : { if (details::is_binary_node ((*vnode)[i])) continue; } break; + case e_function : { if (details::is_function ((*vnode)[i])) continue; } break; + case e_null : { if (details::is_null_node ((*vnode)[i])) continue; } break; + case e_assert : { if (details::is_assert_node ((*vnode)[i])) continue; } break; + case e_sf3ext : { if (details::is_sf3ext_node ((*vnode)[i])) continue; } break; + case e_sf4ext : { if (details::is_sf4ext_node ((*vnode)[i])) continue; } break; + case e_vararg : break; + } + + return false; + } + + return true; } }; template inline bool is_valid(const expression& expr) { - return !expression_helper::is_null(expr); + return expr.control_block_ && !expression_helper::is_null(expr); } namespace parser_error { enum error_mode { - e_unknown = 0, - e_syntax = 1, - e_token = 2, - e_numeric = 4, - e_symtab = 5, - e_lexer = 6, - e_helper = 7, - e_parser = 8 + e_unknown = 0, + e_syntax = 1, + e_token = 2, + e_numeric = 4, + e_symtab = 5, + e_lexer = 6, + e_synthesis = 7, + e_helper = 8, + e_parser = 9 }; struct type @@ -19414,7 +22148,7 @@ namespace exprtk t.token.type = lexer::token::e_error; t.diagnostic = diagnostic; t.src_location = src_location; - exprtk_debug(("%s\n",diagnostic .c_str())); + exprtk_debug(("%s\n", diagnostic .c_str())); return t; } @@ -19428,7 +22162,7 @@ namespace exprtk t.token = tk; t.diagnostic = diagnostic; t.src_location = src_location; - exprtk_debug(("%s\n",diagnostic .c_str())); + exprtk_debug(("%s\n", diagnostic .c_str())); return t; } @@ -19520,70 +22254,79 @@ namespace exprtk e_level10, e_level11, e_level12, e_level13, e_level14 }; - typedef const T& cref_t; - typedef const T const_t; - typedef ifunction F; - typedef ivararg_function VAF; - typedef igeneric_function GF; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::expression_node expression_node_t; - typedef details::literal_node literal_node_t; - typedef details::unary_node unary_node_t; - typedef details::binary_node binary_node_t; - typedef details::trinary_node trinary_node_t; - typedef details::quaternary_node quaternary_node_t; - typedef details::conditional_node conditional_node_t; - typedef details::cons_conditional_node cons_conditional_node_t; - typedef details::while_loop_node while_loop_node_t; - typedef details::repeat_until_loop_node repeat_until_loop_node_t; - typedef details::for_loop_node for_loop_node_t; - typedef details::while_loop_rtc_node while_loop_rtc_node_t; - typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; - typedef details::for_loop_rtc_node for_loop_rtc_node_t; + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction F; + typedef ivararg_function VAF; + typedef igeneric_function GF; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::cons_conditional_node cons_conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::repeat_until_loop_node repeat_until_loop_node_t; + typedef details::for_loop_node for_loop_node_t; + typedef details::while_loop_rtc_node while_loop_rtc_node_t; + typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; + typedef details::for_loop_rtc_node for_loop_rtc_node_t; #ifndef exprtk_disable_break_continue - typedef details::while_loop_bc_node while_loop_bc_node_t; - typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; - typedef details::for_loop_bc_node for_loop_bc_node_t; - typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; - typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; - typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; + typedef details::while_loop_bc_node while_loop_bc_node_t; + typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; + typedef details::for_loop_bc_node for_loop_bc_node_t; + typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; + typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; + typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; #endif - typedef details::switch_node switch_node_t; - typedef details::variable_node variable_node_t; - typedef details::vector_elem_node vector_elem_node_t; - typedef details::rebasevector_elem_node rebasevector_elem_node_t; - typedef details::rebasevector_celem_node rebasevector_celem_node_t; - typedef details::vector_node vector_node_t; - typedef details::range_pack range_t; + typedef details::switch_node switch_node_t; + typedef details::variable_node variable_node_t; + typedef details::vector_elem_node vector_elem_node_t; + typedef details::vector_celem_node vector_celem_node_t; + typedef details::vector_elem_rtc_node vector_elem_rtc_node_t; + typedef details::vector_celem_rtc_node vector_celem_rtc_node_t; + typedef details::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; + typedef details::rebasevector_elem_rtc_node rebasevector_elem_rtc_node_t; + typedef details::rebasevector_celem_rtc_node rebasevector_celem_rtc_node_t; + typedef details::vector_node vector_node_t; + typedef details::vector_size_node vector_size_node_t; + typedef details::range_pack range_t; #ifndef exprtk_disable_string_capabilities - typedef details::stringvar_node stringvar_node_t; - typedef details::string_literal_node string_literal_node_t; - typedef details::string_range_node string_range_node_t; - typedef details::const_string_range_node const_string_range_node_t; - typedef details::generic_string_range_node generic_string_range_node_t; - typedef details::string_concat_node string_concat_node_t; - typedef details::assignment_string_node assignment_string_node_t; - typedef details::assignment_string_range_node assignment_string_range_node_t; - typedef details::conditional_string_node conditional_string_node_t; - typedef details::cons_conditional_str_node cons_conditional_str_node_t; + typedef details::stringvar_node stringvar_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::string_range_node string_range_node_t; + typedef details::const_string_range_node const_string_range_node_t; + typedef details::generic_string_range_node generic_string_range_node_t; + typedef details::string_concat_node string_concat_node_t; + typedef details::assignment_string_node assignment_string_node_t; + typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; #endif - typedef details::assignment_node assignment_node_t; - typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; - typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; - typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; - typedef details::assignment_vec_node assignment_vec_node_t; - typedef details::assignment_vecvec_node assignment_vecvec_node_t; - typedef details::conditional_vector_node conditional_vector_node_t; - typedef details::scand_node scand_node_t; - typedef details::scor_node scor_node_t; - typedef lexer::token token_t; - typedef expression_node_t* expression_node_ptr; - typedef expression expression_t; - typedef symbol_table symbol_table_t; - typedef typename expression::symtab_list_t symbol_table_list_t; - typedef details::vector_holder* vector_holder_ptr; + typedef details::assignment_node assignment_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_vec_elem_rtc_node assignment_vec_elem_rtc_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_elem_rtc_node assignment_rebasevec_elem_rtc_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node assignment_vec_node_t; + typedef details::assignment_vecvec_node assignment_vecvec_node_t; + typedef details::conditional_vector_node conditional_vector_node_t; + typedef details::scand_node scand_node_t; + typedef details::scor_node scor_node_t; + typedef lexer::token token_t; + typedef expression_node_t* expression_node_ptr; + typedef expression expression_t; + typedef symbol_table symbol_table_t; + typedef typename expression::symtab_list_t symbol_table_list_t; + typedef details::vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef typename details::functor_t functor_t; typedef typename functor_t::qfunc_t quaternary_functor_t; @@ -19636,6 +22379,7 @@ namespace exprtk enum element_type { e_none , + e_literal , e_variable, e_vector , e_vecelem , @@ -19643,6 +22387,7 @@ namespace exprtk }; typedef details::vector_holder vector_holder_t; + typedef literal_node_t* literal_node_ptr; typedef variable_node_t* variable_node_ptr; typedef vector_holder_t* vector_holder_ptr; typedef expression_node_t* expression_node_ptr; @@ -19657,8 +22402,8 @@ namespace exprtk , depth(std::numeric_limits::max()) , ref_count(0) , ip_index (0) - , type (e_none) - , active(false) + , type (e_none) + , active (false) , data (0) , var_node (0) , vec_node (0) @@ -19842,6 +22587,10 @@ namespace exprtk switch (se.type) { + case scope_element::e_literal : delete reinterpret_cast(se.data); + delete se.var_node; + break; + case scope_element::e_variable : delete reinterpret_cast(se.data); delete se.var_node; break; @@ -19906,6 +22655,25 @@ namespace exprtk return expression_node_ptr(0); } + inline std::string get_vector_name(const T* data) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if ( + se.active && + se.vec_node && + (se.vec_node->data() == data) + ) + { + return se.name; + } + } + + return "neo-vector"; + } + private: scope_element_manager(const scope_element_manager&) exprtk_delete; @@ -20092,16 +22860,17 @@ namespace exprtk if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) { limit_exceeded_ = true; - parser_.set_error( - make_error(parser_error::e_parser, - "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + - " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_parser, + "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), + exprtk_error_location)); } } ~stack_limit_handler() { + assert(parser_.state_.stack_depth > 0); parser_.state_.stack_depth--; } @@ -20211,22 +22980,23 @@ namespace exprtk inline variable_context get_variable_context(const std::string& variable_name) const { variable_context result; - if (!valid_symbol(variable_name)) - return result; - for (std::size_t i = 0; i < symtab_list_.size(); ++i) + if (valid_symbol(variable_name)) { - if (!symtab_list_[i].valid()) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - continue; - } + if (!symtab_list_[i].valid()) + { + continue; + } - result.variable = local_data(i) - .variable_store.get(variable_name); - if (result.variable) - { - result.symbol_table = &symtab_list_[i]; - break; + result.variable = local_data(i) + .variable_store.get(variable_name); + if (result.variable) + { + result.symbol_table = &symtab_list_[i]; + break; + } } } @@ -20461,12 +23231,16 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else - result = - local_data(i).vector_store.get(vector_name); + } - if (result) break; + result = local_data(i).vector_store.get(vector_name); + + if (result) + { + break; + } } return result; @@ -20480,9 +23254,14 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else if (local_data(i).variable_store.is_constant(symbol_name)) + } + + if (local_data(i).variable_store.is_constant(symbol_name)) + { return true; + } } return false; @@ -20513,9 +23292,14 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else if (symtab_list_[i].symbol_exists(symbol)) + } + + if (symtab_list_[i].symbol_exists(symbol)) + { return true; + } } return false; @@ -20675,6 +23459,7 @@ namespace exprtk { parsing_return_stmt = false; parsing_break_stmt = false; + parsing_assert_stmt = false; return_stmt_present = false; side_effect_present = false; scope_depth = 0; @@ -20692,12 +23477,13 @@ namespace exprtk { side_effect_present = true; - exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + exprtk_debug(("activate_side_effect() - caller: %s\n", source.c_str())); } } bool parsing_return_stmt; bool parsing_break_stmt; + bool parsing_assert_stmt; bool return_stmt_present; bool side_effect_present; bool type_check_enabled; @@ -20730,7 +23516,8 @@ namespace exprtk : mode(m) {} - virtual ~unknown_symbol_resolver() {} + virtual ~unknown_symbol_resolver() + {} virtual bool process(const std::string& /*unknown_symbol*/, usr_symbol_type& st, @@ -20806,11 +23593,14 @@ namespace exprtk details::case_normalise(symbol_name_list_[i].first); } - std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); + std::sort(symbol_name_list_.begin(), symbol_name_list_.end()); - std::unique_copy(symbol_name_list_.begin(), - symbol_name_list_.end (), - std::back_inserter(symbols_list)); + std::unique_copy + ( + symbol_name_list_.begin(), + symbol_name_list_.end (), + std::back_inserter(symbols_list) + ); return symbols_list.size(); } @@ -20831,9 +23621,12 @@ namespace exprtk std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - std::unique_copy(assignment_name_list_.begin(), - assignment_name_list_.end (), - std::back_inserter(assignment_list)); + std::unique_copy + ( + assignment_name_list_.begin(), + assignment_name_list_.end (), + std::back_inserter(assignment_list) + ); return assignment_list.size(); } @@ -21020,7 +23813,7 @@ namespace exprtk e_ineq_gte , e_ineq_gt }; - static const std::size_t compile_all_opts = + static const std::size_t default_compile_all_opts = e_replacer + e_joiner + e_numeric_check + @@ -21029,9 +23822,10 @@ namespace exprtk e_commutative_check + e_strength_reduction; - settings_store(const std::size_t compile_options = compile_all_opts) + settings_store(const std::size_t compile_options = default_compile_all_opts) : max_stack_depth_(400) , max_node_depth_(10000) + , max_local_vector_size_(2000000000) { load_compile_options(compile_options); } @@ -21078,12 +23872,24 @@ namespace exprtk return (*this); } + settings_store& enable_commutative_check() + { + enable_commutative_check_ = true; + return (*this); + } + + settings_store& enable_strength_reduction() + { + enable_strength_reduction_ = true; + return (*this); + } + settings_store& disable_all_base_functions() { std::copy(details::base_function_list, details::base_function_list + details::base_function_list_size, std::insert_iterator - (disabled_func_set_, disabled_func_set_.begin())); + (disabled_func_set_, disabled_func_set_.begin())); return (*this); } @@ -21092,7 +23898,7 @@ namespace exprtk std::copy(details::cntrl_struct_list, details::cntrl_struct_list + details::cntrl_struct_list_size, std::insert_iterator - (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); return (*this); } @@ -21110,7 +23916,7 @@ namespace exprtk std::copy(details::arithmetic_ops_list, details::arithmetic_ops_list + details::arithmetic_ops_list_size, std::insert_iterator - (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); return (*this); } @@ -21119,7 +23925,7 @@ namespace exprtk std::copy(details::assignment_ops_list, details::assignment_ops_list + details::assignment_ops_list_size, std::insert_iterator - (disabled_assignment_set_, disabled_assignment_set_.begin())); + (disabled_assignment_set_, disabled_assignment_set_.begin())); return (*this); } @@ -21128,7 +23934,7 @@ namespace exprtk std::copy(details::inequality_ops_list, details::inequality_ops_list + details::inequality_ops_list_size, std::insert_iterator - (disabled_inequality_set_, disabled_inequality_set_.begin())); + (disabled_inequality_set_, disabled_inequality_set_.begin())); return (*this); } @@ -21138,6 +23944,18 @@ namespace exprtk return (*this); } + settings_store& disable_commutative_check() + { + enable_commutative_check_ = false; + return (*this); + } + + settings_store& disable_strength_reduction() + { + enable_strength_reduction_ = false; + return (*this); + } + bool replacer_enabled () const { return enable_replacer_; } bool commutative_check_enabled () const { return enable_commutative_check_; } bool joiner_enabled () const { return enable_joiner_; } @@ -21263,7 +24081,7 @@ namespace exprtk .find(inequality_opr_to_string(inequality)); } - settings_store& disable_base_function(settings_base_funcs bf) + settings_store& disable_base_function(const settings_base_funcs bf) { if ( (e_bf_unknown != bf) && @@ -21276,7 +24094,7 @@ namespace exprtk return (*this); } - settings_store& disable_control_structure(settings_control_structs ctrl_struct) + settings_store& disable_control_structure(const settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && @@ -21289,7 +24107,7 @@ namespace exprtk return (*this); } - settings_store& disable_logic_operation(settings_logic_opr logic) + settings_store& disable_logic_operation(const settings_logic_opr logic) { if ( (e_logic_unknown != logic) && @@ -21302,7 +24120,7 @@ namespace exprtk return (*this); } - settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + settings_store& disable_arithmetic_operation(const settings_arithmetic_opr arithmetic) { if ( (e_arith_unknown != arithmetic) && @@ -21315,7 +24133,7 @@ namespace exprtk return (*this); } - settings_store& disable_assignment_operation(settings_assignment_opr assignment) + settings_store& disable_assignment_operation(const settings_assignment_opr assignment) { if ( (e_assign_unknown != assignment) && @@ -21328,7 +24146,7 @@ namespace exprtk return (*this); } - settings_store& disable_inequality_operation(settings_inequality_opr inequality) + settings_store& disable_inequality_operation(const settings_inequality_opr inequality) { if ( (e_ineq_unknown != inequality) && @@ -21341,7 +24159,7 @@ namespace exprtk return (*this); } - settings_store& enable_base_function(settings_base_funcs bf) + settings_store& enable_base_function(const settings_base_funcs bf) { if ( (e_bf_unknown != bf) && @@ -21359,7 +24177,7 @@ namespace exprtk return (*this); } - settings_store& enable_control_structure(settings_control_structs ctrl_struct) + settings_store& enable_control_structure(const settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && @@ -21377,7 +24195,7 @@ namespace exprtk return (*this); } - settings_store& enable_logic_operation(settings_logic_opr logic) + settings_store& enable_logic_operation(const settings_logic_opr logic) { if ( (e_logic_unknown != logic) && @@ -21395,7 +24213,7 @@ namespace exprtk return (*this); } - settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) + settings_store& enable_arithmetic_operation(const settings_arithmetic_opr arithmetic) { if ( (e_arith_unknown != arithmetic) && @@ -21413,7 +24231,7 @@ namespace exprtk return (*this); } - settings_store& enable_assignment_operation(settings_assignment_opr assignment) + settings_store& enable_assignment_operation(const settings_assignment_opr assignment) { if ( (e_assign_unknown != assignment) && @@ -21431,7 +24249,7 @@ namespace exprtk return (*this); } - settings_store& enable_inequality_operation(settings_inequality_opr inequality) + settings_store& enable_inequality_operation(const settings_inequality_opr inequality) { if ( (e_ineq_unknown != inequality) && @@ -21459,6 +24277,26 @@ namespace exprtk max_node_depth_ = max_node_depth; } + void set_max_local_vector_size(const std::size_t max_local_vector_size) + { + max_local_vector_size_ = max_local_vector_size; + } + + std::size_t max_stack_depth() const + { + return max_stack_depth_; + } + + std::size_t max_node_depth() const + { + return max_node_depth_; + } + + std::size_t max_local_vector_size() const + { + return max_local_vector_size_; + } + private: void load_compile_options(const std::size_t compile_options) @@ -21501,6 +24339,7 @@ namespace exprtk case details::e_mul : return "*"; case details::e_div : return "/"; case details::e_mod : return "%"; + case details::e_pow : return "^"; default : return "" ; } } @@ -21559,13 +24398,14 @@ namespace exprtk std::size_t max_stack_depth_; std::size_t max_node_depth_; + std::size_t max_local_vector_size_; friend class parser; }; typedef settings_store settings_t; - parser(const settings_t& settings = settings_t()) + explicit parser(const settings_t& settings = settings_t()) : settings_(settings) , resolve_unknown_symbol_(false) , results_context_(0) @@ -21581,6 +24421,9 @@ namespace exprtk , operator_joiner_2_(2) , operator_joiner_3_(3) , loop_runtime_check_(0) + , vector_access_runtime_check_(0) + , compilation_check_ptr_(0) + , assert_check_(0) { init_precompilation(); @@ -21593,15 +24436,16 @@ namespace exprtk expression_generator_.init_synthesize_map(); expression_generator_.set_parser(*this); - expression_generator_.set_uom(unary_op_map_); - expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_uom (unary_op_map_ ); + expression_generator_.set_bom (binary_op_map_ ); expression_generator_.set_ibom(inv_binary_op_map_); - expression_generator_.set_sf3m(sf3_map_); - expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_sf3m(sf3_map_ ); + expression_generator_.set_sf4m(sf4_map_ ); expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); } - ~parser() {} + ~parser() + {} inline void init_precompilation() { @@ -21669,11 +24513,15 @@ namespace exprtk inline bool compile(const std::string& expression_string, expression& expr) { - state_ .reset(); - error_list_ .clear(); - brkcnt_list_ .clear(); - synthesis_error_.clear(); - sem_ .cleanup(); + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_ .clear(); + immutable_memory_map_.reset(); + immutable_symtok_map_.clear(); + current_state_stack_ .clear(); + assert_ids_ .clear(); + sem_ .cleanup(); return_cleanup(); @@ -21681,10 +24529,10 @@ namespace exprtk if (expression_string.empty()) { - set_error( - make_error(parser_error::e_syntax, - "ERR001 - Empty expression!", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + "ERR001 - Empty expression!", + exprtk_error_location)); return false; } @@ -21697,19 +24545,31 @@ namespace exprtk if (lexer().empty()) { - set_error( - make_error(parser_error::e_syntax, - "ERR002 - Empty expression!", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + "ERR002 - Empty expression!", + exprtk_error_location)); return false; } + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - compile checkpoint 0\n")); + return false; + } + if (!run_assemblies()) { return false; } + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - compile checkpoint 1\n")); + return false; + } + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); dec_.clear(); @@ -21743,11 +24603,11 @@ namespace exprtk { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR003 - Invalid expression encountered", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR003 - Invalid expression encountered", + exprtk_error_location)); } if ((0 != e) && branch_deletable(e)) @@ -21799,11 +24659,11 @@ namespace exprtk default : diagnostic += "Unknown compiler error"; } - set_error( - make_error(parser_error::e_lexer, - lexer()[i], - diagnostic + ": " + lexer()[i].value, - exprtk_error_location)); + set_error(make_error( + parser_error::e_lexer, + lexer()[i], + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); } } } @@ -21842,11 +24702,11 @@ namespace exprtk if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) { - set_error( - make_error(parser_error::e_token, - bracket_checker_ptr->error_token(), - "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + bracket_checker_ptr->error_token(), + "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + exprtk_error_location)); } else if (0 != (numeric_checker_ptr = dynamic_cast*>(helper_assembly_.error_token_scanner))) { @@ -21854,11 +24714,11 @@ namespace exprtk { lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; - set_error( - make_error(parser_error::e_token, - error_token, - "ERR006 - Invalid numeric token: '" + error_token.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token, + "ERR006 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); } if (numeric_checker_ptr->error_count()) @@ -21872,13 +24732,13 @@ namespace exprtk { std::pair error_token = sequence_validator_ptr->error(i); - set_error( - make_error(parser_error::e_token, - error_token.first, - "ERR007 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); } if (sequence_validator_ptr->error_count()) @@ -21892,13 +24752,13 @@ namespace exprtk { std::pair error_token = sequence_validator3_ptr->error(i); - set_error( - make_error(parser_error::e_token, - error_token.first, - "ERR008 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token.first, + "ERR008 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); } if (sequence_validator3_ptr->error_count()) @@ -21923,9 +24783,11 @@ namespace exprtk inline parser_error::type get_error(const std::size_t& index) const { if (index < error_list_.size()) + { return error_list_[index]; - else - throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); + } + + throw std::invalid_argument("parser::get_error() - Invalid error index specified"); } inline std::string error() const @@ -21994,11 +24856,41 @@ namespace exprtk loop_runtime_check_ = &lrtchk; } + inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) + { + vector_access_runtime_check_ = &vartchk; + } + + inline void register_compilation_timeout_check(compilation_check& compchk) + { + compilation_check_ptr_ = &compchk; + } + + inline void register_assert_check(assert_check& assrt_chck) + { + assert_check_ = &assrt_chck; + } + inline void clear_loop_runtime_check() { loop_runtime_check_ = loop_runtime_check_ptr(0); } + inline void clear_vector_access_runtime_check() + { + vector_access_runtime_check_ = vector_access_runtime_check_ptr(0); + } + + inline void clear_compilation_timeout_check() + { + compilation_check_ptr_ = compilation_check_ptr(0); + } + + inline void clear_assert_check() + { + assert_check_ = assert_check_ptr(0); + } + private: inline bool valid_base_operation(const std::string& symbol) const @@ -22102,11 +24994,11 @@ namespace exprtk { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR009 - Invalid expression encountered", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR009 - Invalid expression encountered", + exprtk_error_location)); } return error_node(); @@ -22132,15 +25024,31 @@ namespace exprtk exprtk_debug(("-------------------------------------------------\n")); } - if (lexer().finished()) - break; - else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { if (lexer().finished()) break; else next_token(); } + else if ( + !settings_.commutative_check_enabled() && + ( + current_token().type == token_t::e_symbol || + current_token().type == token_t::e_number || + current_token().type == token_t::e_string || + token_is_bracket(prsrhlpr_t::e_hold) + ) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR010 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + return error_node(); + } } if ( @@ -22158,13 +25066,17 @@ namespace exprtk return result; } - std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + std::string construct_subexpr(lexer::token& begin_token, + lexer::token& end_token, + const bool cleanup_whitespace = true) { std::string result = lexer().substr(begin_token.position,end_token.position); - - for (std::size_t i = 0; i < result.size(); ++i) + if (cleanup_whitespace) { - if (details::is_whitespace(result[i])) result[i] = ' '; + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } } return result; @@ -22176,11 +25088,13 @@ namespace exprtk { inline void set(const precedence_level& l, const precedence_level& r, - const details::operator_type& o) + const details::operator_type& o, + const token_t tkn = token_t()) { - left = l; - right = r; + left = l; + right = r; operation = o; + token = tkn; } inline void reset() @@ -22193,10 +25107,58 @@ namespace exprtk precedence_level left; precedence_level right; details::operator_type operation; + token_t token; }; + inline void push_current_state(const state_t current_state) + { + current_state_stack_.push_back(current_state); + } + + inline void pop_current_state() + { + if (!current_state_stack_.empty()) + { + current_state_stack_.pop_back(); + } + } + + inline state_t current_state() const + { + return (!current_state_stack_.empty()) ? + current_state_stack_.back() : + state_t(); + } + + inline bool halt_compilation_check() + { + compilation_check::compilation_context context; + + if (compilation_check_ptr_ && !compilation_check_ptr_->continue_compilation(context)) + { + const std::string error_message = + !context.error_message.empty() ? " Details: " + context.error_message : ""; + + set_error(make_error( + parser_error::e_parser, + token_t(), + "ERR011 - Internal compilation check failed." + error_message, + exprtk_error_location)); + + return true; + } + + return false; + } + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - parse_expression checkpoint 2\n")); + return error_node(); + } + stack_limit_handler slh(*this); if (!slh) @@ -22211,6 +25173,11 @@ namespace exprtk return error_node(); } + if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + return expression; + } + bool break_loop = false; state_t current_state; @@ -22221,110 +25188,111 @@ namespace exprtk switch (current_token().type) { - case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign); break; - case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass); break; - case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass); break; - case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass); break; - case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass); break; - case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass); break; - case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap ); break; - case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt ); break; - case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte ); break; - case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq ); break; - case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne ); break; - case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte ); break; - case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt ); break; - case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add ); break; - case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub ); break; - case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div ); break; - case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul ); break; - case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod ); break; - case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow ); break; - default : if (token_t::e_symbol == current_token().type) - { - static const std::string s_and = "and" ; - static const std::string s_nand = "nand" ; - static const std::string s_or = "or" ; - static const std::string s_nor = "nor" ; - static const std::string s_xor = "xor" ; - static const std::string s_xnor = "xnor" ; - static const std::string s_in = "in" ; - static const std::string s_like = "like" ; - static const std::string s_ilike = "ilike"; - static const std::string s_and1 = "&" ; - static const std::string s_or1 = "|" ; - static const std::string s_not = "not" ; - - if (details::imatch(current_token().value,s_and)) - { - current_state.set(e_level03, e_level04, details::e_and); - break; - } - else if (details::imatch(current_token().value,s_and1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level03, e_level04, details::e_scand); - #else - current_state.set(e_level03, e_level04, details::e_and); - #endif - break; - } - else if (details::imatch(current_token().value,s_nand)) - { - current_state.set(e_level03, e_level04, details::e_nand); - break; - } - else if (details::imatch(current_token().value,s_or)) - { - current_state.set(e_level01, e_level02, details::e_or); - break; - } - else if (details::imatch(current_token().value,s_or1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level01, e_level02, details::e_scor); - #else - current_state.set(e_level01, e_level02, details::e_or); - #endif - break; - } - else if (details::imatch(current_token().value,s_nor)) - { - current_state.set(e_level01, e_level02, details::e_nor); - break; - } - else if (details::imatch(current_token().value,s_xor)) - { - current_state.set(e_level01, e_level02, details::e_xor); - break; - } - else if (details::imatch(current_token().value,s_xnor)) - { - current_state.set(e_level01, e_level02, details::e_xnor); - break; - } - else if (details::imatch(current_token().value,s_in)) - { - current_state.set(e_level04, e_level04, details::e_in); - break; - } - else if (details::imatch(current_token().value,s_like)) - { - current_state.set(e_level04, e_level04, details::e_like); - break; - } - else if (details::imatch(current_token().value,s_ilike)) - { - current_state.set(e_level04, e_level04, details::e_ilike); - break; - } - else if (details::imatch(current_token().value,s_not)) - { - break; - } - } - - break_loop = true; + case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign, current_token()); break; + case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass, current_token()); break; + case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass, current_token()); break; + case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass, current_token()); break; + case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass, current_token()); break; + case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass, current_token()); break; + case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap , current_token()); break; + case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt , current_token()); break; + case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte , current_token()); break; + case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq , current_token()); break; + case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne , current_token()); break; + case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte , current_token()); break; + case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt , current_token()); break; + case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add , current_token()); break; + case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub , current_token()); break; + case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div , current_token()); break; + case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul , current_token()); break; + case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod , current_token()); break; + case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow , current_token()); break; + default : + if (token_t::e_symbol == current_token().type) + { + static const std::string s_and = "and" ; + static const std::string s_nand = "nand" ; + static const std::string s_or = "or" ; + static const std::string s_nor = "nor" ; + static const std::string s_xor = "xor" ; + static const std::string s_xnor = "xnor" ; + static const std::string s_in = "in" ; + static const std::string s_like = "like" ; + static const std::string s_ilike = "ilike"; + static const std::string s_and1 = "&" ; + static const std::string s_or1 = "|" ; + static const std::string s_not = "not" ; + + if (details::imatch(current_token().value,s_and)) + { + current_state.set(e_level03, e_level04, details::e_and, current_token()); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03, e_level04, details::e_scand, current_token()); + #else + current_state.set(e_level03, e_level04, details::e_and, current_token()); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03, e_level04, details::e_nand, current_token()); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01, e_level02, details::e_or, current_token()); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01, e_level02, details::e_scor, current_token()); + #else + current_state.set(e_level01, e_level02, details::e_or, current_token()); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01, e_level02, details::e_nor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01, e_level02, details::e_xor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01, e_level02, details::e_xnor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04, e_level04, details::e_in, current_token()); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04, e_level04, details::e_like, current_token()); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04, e_level04, details::e_ilike, current_token()); + break; + } + else if (details::imatch(current_token().value,s_not)) + { + break; + } + } + + break_loop = true; } if (break_loop) @@ -22344,49 +25312,49 @@ namespace exprtk if (is_invalid_logic_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR012 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_arithmetic_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR013 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_inequality_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR014 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_assignment_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR015 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -22401,34 +25369,38 @@ namespace exprtk free_node(node_allocator_, expression ); free_node(node_allocator_, right_branch); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR014 - Return statements cannot be part of sub-expressions", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR016 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); return error_node(); } + push_current_state(current_state); + new_expression = expression_generator_ ( current_state.operation, expression, right_branch ); + + pop_current_state(); } if (0 == new_expression) { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - prev_token, - !synthesis_error_.empty() ? - synthesis_error_ : - "ERR015 - General parsing error at token: '" + prev_token.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR017 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); } free_node(node_allocator_, expression ); @@ -22454,14 +25426,35 @@ namespace exprtk if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + - " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR018 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); + + return error_node(); + } + else if ( + !settings_.commutative_check_enabled() && + !details::is_logic_opr(current_token().value) && + (current_state.operation == details::e_default) && + ( + current_token().type == token_t::e_symbol || + current_token().type == token_t::e_number || + current_token().type == token_t::e_string + ) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR019 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + free_node(node_allocator_, expression); return error_node(); } @@ -22479,7 +25472,7 @@ namespace exprtk { expression_node_ptr un_r = n->branch(0); n->release(); - free_node(node_allocator_,node); + free_node(node_allocator_, node); node = un_r; return true; @@ -22501,20 +25494,20 @@ namespace exprtk (0 != (return_node = sem_ .get_variable(v))) ) { - free_node(node_allocator_,node); + free_node(node_allocator_, node); node = return_node; return true; } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR017 - Failed to find variable node in symbol table", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR020 - Failed to find variable node in symbol table", + exprtk_error_location)); - free_node(node_allocator_,node); + free_node(node_allocator_, node); return false; } @@ -22610,6 +25603,7 @@ namespace exprtk { for (std::size_t i = 0; i < deq_.size(); ++i) { + exprtk_debug(("~scoped_deq_delete() - deleting node: %p\n", reinterpret_cast(deq_[i]))); free_node(parser_.node_allocator_,deq_[i]); } @@ -22644,6 +25638,7 @@ namespace exprtk { for (std::size_t i = 0; i < vec_.size(); ++i) { + exprtk_debug(("~scoped_vec_delete() - deleting node: %p\n", reinterpret_cast(vec_[i]))); free_node(parser_.node_allocator_,vec_[i]); } @@ -22651,6 +25646,11 @@ namespace exprtk } } + ptr_t operator[](const std::size_t index) + { + return vec_[index]; + } + bool delete_ptr; parser& parser_; std::vector& vec_; @@ -22732,11 +25732,11 @@ namespace exprtk case 19 : func_node = parse_function_call<19>(function,function_name); break; case 20 : func_node = parse_function_call<20>(function,function_name); break; default : { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR018 - Invalid number of parameters for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR021 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22746,11 +25746,11 @@ namespace exprtk return func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR019 - Failed to generate call to function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR022 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22765,11 +25765,11 @@ namespace exprtk #endif if (0 == NumberofParameters) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR023 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); return error_node(); } @@ -22788,11 +25788,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR021 - Expecting argument list for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR024 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22803,11 +25803,11 @@ namespace exprtk if (0 == branch[i]) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR025 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22815,11 +25815,11 @@ namespace exprtk { if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR023 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR026 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22828,11 +25828,11 @@ namespace exprtk if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR024 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR027 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22857,13 +25857,13 @@ namespace exprtk !token_is(token_t::e_rbracket) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR028 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return error_node(); } @@ -22882,23 +25882,23 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR026 - Expected a '(' at start of function call to '" + function_name + - "', instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR029 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } if (token_is(token_t::e_rbracket, e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR030 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22920,11 +25920,11 @@ namespace exprtk continue; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR031 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } @@ -22932,11 +25932,11 @@ namespace exprtk if (sd.delete_ptr) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR032 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22955,11 +25955,11 @@ namespace exprtk if (0 == std::distance(itr_range.first,itr_range.second)) { - set_error( - make_error(parser_error::e_syntax, - diagnostic_token, - "ERR030 - No entry found for base operation: " + operation_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + diagnostic_token, + "ERR033 - No entry found for base operation: " + operation_name, + exprtk_error_location)); return error_node(); } @@ -23002,11 +26002,11 @@ namespace exprtk free_node(node_allocator_, param_list[i]); } - set_error( - make_error(parser_error::e_syntax, - diagnostic_token, - "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + diagnostic_token, + "ERR034 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); return error_node(); } @@ -23022,47 +26022,52 @@ namespace exprtk if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR032 - Expected ',' between if-statement condition and consequent", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR035 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); + result = false; } else if (0 == (consequent = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR033 - Failed to parse consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR036 - Failed to parse consequent for if-statement", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR034 - Expected ',' between if-statement consequent and alternative", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR037 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); + result = false; } else if (0 == (alternative = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR035 - Failed to parse alternative for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR038 - Failed to parse alternative for if-statement", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR036 - Expected ')' at the end of if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR039 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; } @@ -23076,15 +26081,30 @@ namespace exprtk { if (consq_is_str && alter_is_str) { - return expression_generator_ - .conditional_string(condition, consequent, alternative); + expression_node_ptr result_node = + expression_generator_ + .conditional_string(condition, consequent, alternative); + + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR040 - Failed to synthesize node: conditional_string", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + return error_node(); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR037 - Return types of if-statement differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR041 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23104,11 +26124,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR038 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR042 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23138,11 +26158,31 @@ namespace exprtk { if (0 == (consequent = parse_multi_sequence("if-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR039 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR043 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + else if + ( + !settings_.commutative_check_enabled() && + !token_is("else",prsrhlpr_t::e_hold) && + !token_is_loop(prsrhlpr_t::e_hold) && + !token_is_arithmetic_opr(prsrhlpr_t::e_hold) && + !token_is_right_bracket (prsrhlpr_t::e_hold) && + !token_is_ineq_opr (prsrhlpr_t::e_hold) && + !token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + !token_is(token_t::e_eof ,prsrhlpr_t::e_hold) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR044 - Expected ';' at the end of the consequent for if-statement (1)", + exprtk_error_location)); result = false; } @@ -23159,24 +26199,24 @@ namespace exprtk if (0 != (consequent = parse_expression())) { - if (!token_is(token_t::e_eof)) + if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR040 - Expected ';' at the end of the consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR045 - Expected ';' at the end of the consequent for if-statement (2)", + exprtk_error_location)); result = false; } } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR041 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR046 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); result = false; } @@ -23184,19 +26224,27 @@ namespace exprtk if (result) { - if (details::imatch(current_token().value,"else")) + if ( + details::imatch(current_token().value,"else") || + (token_is(token_t::e_eof, prsrhlpr_t::e_hold) && peek_token_is("else")) + ) { next_token(); + if (details::imatch(current_token().value,"else")) + { + next_token(); + } + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) { if (0 == (alternative = parse_multi_sequence("else-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR042 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR047 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -23205,35 +26253,39 @@ namespace exprtk { if (0 == (alternative = parse_conditional_statement())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR043 - Failed to parse body of if-else statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR048 - Failed to parse body of if-else statement", + exprtk_error_location)); result = false; } } else if (0 != (alternative = parse_expression())) { - if (!token_is(token_t::e_eof)) + if ( + !token_is(token_t::e_ternary , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_eof) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR044 - Expected ';' at the end of the 'else-if' for the if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR049 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); result = false; } } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR045 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR050 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -23254,11 +26306,11 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR046 - Return types of if-statement differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR051 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23278,11 +26330,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR047 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR052 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23309,21 +26361,21 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR048 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR053 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR049 - Failed to parse condition for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR054 - Failed to parse condition for if-statement", + exprtk_error_location)); return error_node(); } @@ -23353,13 +26405,13 @@ namespace exprtk return parse_conditional_statement_02(condition); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR050 - Invalid if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR055 - Invalid if-statement", + exprtk_error_location)); - free_node(node_allocator_,condition); + free_node(node_allocator_, condition); return error_node(); } @@ -23374,51 +26426,51 @@ namespace exprtk if (0 == condition) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR051 - Encountered invalid condition branch for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR056 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_ternary)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR052 - Expected '?' after condition of ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR057 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); result = false; } else if (0 == (consequent = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR053 - Failed to parse consequent for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR058 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR054 - Expected ':' between ternary if-statement consequent and alternative", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR059 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); result = false; } else if (0 == (alternative = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR055 - Failed to parse alternative for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR060 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); result = false; } @@ -23437,11 +26489,11 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR056 - Return types of ternary differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR061 - Return types of ternary differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23461,11 +26513,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR057 - Return types of ternary differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR062 - Return types of ternary differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23488,11 +26540,11 @@ namespace exprtk { if (settings_.logic_disabled("not")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR058 - Invalid or disabled logic operation 'not'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR063 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); return error_node(); } @@ -23519,31 +26571,31 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR059 - Expected '(' at start of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR064 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR060 - Failed to parse condition for while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR065 - Failed to parse condition for while-loop", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR061 - Expected ')' at end of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR066 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); result = false; } @@ -23556,21 +26608,21 @@ namespace exprtk if (0 == (branch = parse_multi_sequence("while-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR062 - Failed to parse body of while-loop")); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR067 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, branch, brkcnt_list_.front()))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR063 - Failed to synthesize while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR068 - Failed to synthesize while-loop", + exprtk_error_location)); result = false; } @@ -23587,7 +26639,20 @@ namespace exprtk return error_node(); } - return result_node; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR069 - Failed to synthesize 'valid' while-loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_repeat_until_loop() @@ -23611,7 +26676,7 @@ namespace exprtk } else { - const token_t::token_type seperator = token_t::e_eof; + const token_t::token_type separator = token_t::e_eof; scope_handler sh(*this); @@ -23642,13 +26707,13 @@ namespace exprtk const bool is_next_until = peek_token_is(token_t::e_symbol) && peek_token_is("until"); - if (!token_is(seperator) && is_next_until) + if (!token_is(separator) && is_next_until) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR064 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR070 - Expected '" + token_t::to_str(separator) + "' in body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -23666,11 +26731,11 @@ namespace exprtk if (sdd.delete_ptr) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR065 - Failed to parse body of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR071 - Failed to parse body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -23678,33 +26743,33 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR066 - Expected '(' before condition statement of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR072 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,branch); + free_node(node_allocator_, branch); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR067 - Failed to parse condition for repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR073 - Failed to parse condition for repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,branch); + free_node(node_allocator_, branch); return error_node(); } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR068 - Expected ')' after condition of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR074 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); free_node(node_allocator_, branch ); free_node(node_allocator_, condition); @@ -23712,27 +26777,42 @@ namespace exprtk return error_node(); } - expression_node_ptr result; - - result = expression_generator_ - .repeat_until_loop(condition, branch, brkcnt_list_.front()); + expression_node_ptr result_node = + expression_generator_ + .repeat_until_loop( + condition, + branch, + brkcnt_list_.front()); - if (0 == result) + if (0 == result_node) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR069 - Failed to synthesize repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR075 - Failed to synthesize repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,condition); + free_node(node_allocator_, condition); return error_node(); } handle_brkcnt_scope_exit(); - return result; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR076 - Failed to synthesize 'valid' repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_for_loop() @@ -23751,11 +26831,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR070 - Expected '(' at start of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR077 - Expected '(' at start of for-loop", + exprtk_error_location)); return error_node(); } @@ -23771,21 +26851,21 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR071 - Expected a variable at the start of initialiser section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR078 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } else if (!peek_token_is(token_t::e_assign)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR072 - Expected variable assignment of initialiser section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR079 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } @@ -23796,11 +26876,11 @@ namespace exprtk if ((se->name == loop_counter_symbol) && se->active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR073 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR080 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); return error_node(); } @@ -23828,11 +26908,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR074 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR081 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -23840,7 +26920,7 @@ namespace exprtk } else { - exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n", nse.name.c_str())); state_.activate_side_effect("parse_for_loop()"); } @@ -23850,21 +26930,21 @@ namespace exprtk if (0 == (initialiser = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR075 - Failed to parse initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR082 - Failed to parse initialiser of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR076 - Expected ';' after initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR083 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); result = false; } @@ -23874,21 +26954,21 @@ namespace exprtk { if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR077 - Failed to parse condition of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR084 - Failed to parse condition of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR078 - Expected ';' after condition section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR085 - Expected ';' after condition section of for-loop", + exprtk_error_location)); result = false; } @@ -23898,21 +26978,21 @@ namespace exprtk { if (0 == (incrementor = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR079 - Failed to parse incrementor of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR086 - Failed to parse incrementor of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR080 - Expected ')' after incrementor section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR087 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); result = false; } @@ -23926,11 +27006,11 @@ namespace exprtk if (0 == (loop_body = parse_multi_sequence("for-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR081 - Failed to parse body of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR088 - Failed to parse body of for-loop", + exprtk_error_location)); result = false; } @@ -23958,7 +27038,20 @@ namespace exprtk brkcnt_list_.front()); handle_brkcnt_scope_exit(); - return result_node; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR089 - Failed to synthesize 'valid' for-loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_switch_statement() @@ -23968,11 +27061,11 @@ namespace exprtk if (!details::imatch(current_token().value,"switch")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR082 - Expected keyword 'switch'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR090 - Expected keyword 'switch'", + exprtk_error_location)); return error_node(); } @@ -23983,11 +27076,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR083 - Expected '{' for call to switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR091 - Expected '{' for call to switch statement", + exprtk_error_location)); return error_node(); } @@ -24008,18 +27101,21 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR084 - Expected ':' for case of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR092 - Expected ':' for case of switch statement", + exprtk_error_location)); free_node(node_allocator_, condition); return error_node(); } - expression_node_ptr consequent = parse_expression(); + expression_node_ptr consequent = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("switch-consequent") : + parse_expression(); if (0 == consequent) { @@ -24029,11 +27125,11 @@ namespace exprtk } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR085 - Expected ';' at end of case for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR093 - Expected ';' at end of case for switch statement", + exprtk_error_location)); free_node(node_allocator_, condition ); free_node(node_allocator_, consequent); @@ -24058,11 +27154,11 @@ namespace exprtk { if (0 != default_statement) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR086 - Multiple default cases for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR094 - Multiple default cases for switch statement", + exprtk_error_location)); return error_node(); } @@ -24071,29 +27167,29 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR087 - Expected ':' for default of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR095 - Expected ':' for default of switch statement", + exprtk_error_location)); return error_node(); } - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - default_statement = parse_multi_sequence("switch-default"); - else - default_statement = parse_expression(); + default_statement = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("switch-default"): + parse_expression(); if (0 == default_statement) return error_node(); else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR088 - Expected ';' at end of default for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR096 - Expected ';' at end of default for switch statement", + exprtk_error_location)); return error_node(); } @@ -24102,11 +27198,11 @@ namespace exprtk break; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR089 - Expected '}' at end of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR097 - Expected '}' at end of switch statement", + exprtk_error_location)); return error_node(); } @@ -24118,6 +27214,10 @@ namespace exprtk { arg_list.push_back(default_statement); } + else + { + arg_list.push_back(node_allocator_.allocate_c(std::numeric_limits::quiet_NaN())); + } result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); @@ -24133,11 +27233,11 @@ namespace exprtk if (!details::imatch(current_token().value,"[*]")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR090 - Expected token '[*]'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR098 - Expected token '[*]'", + exprtk_error_location)); return error_node(); } @@ -24148,11 +27248,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR091 - Expected '{' for call to [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR099 - Expected '{' for call to [*] statement", + exprtk_error_location)); return error_node(); } @@ -24161,11 +27261,11 @@ namespace exprtk { if (!details::imatch("case",current_token().value)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR092 - Expected a 'case' statement for multi-switch", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR100 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); return error_node(); } @@ -24179,27 +27279,30 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR093 - Expected ':' for case of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR101 - Expected ':' for case of [*] statement", + exprtk_error_location)); return error_node(); } - expression_node_ptr consequent = parse_expression(); + expression_node_ptr consequent = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("multi-switch-consequent") : + parse_expression(); if (0 == consequent) return error_node(); if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR094 - Expected ';' at end of case for [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR102 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); return error_node(); } @@ -24224,11 +27327,11 @@ namespace exprtk if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR095 - Expected '}' at end of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR103 - Expected '}' at end of [*] statement", + exprtk_error_location)); return error_node(); } @@ -24250,11 +27353,11 @@ namespace exprtk if (details::imatch(symbol,"~")) { next_token(); - return parse_multi_sequence(); + return check_block_statement_closure(parse_multi_sequence()); } else if (details::imatch(symbol,"[*]")) { - return parse_multi_switch_statement(); + return check_block_statement_closure(parse_multi_switch_statement()); } else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; @@ -24265,11 +27368,11 @@ namespace exprtk else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR096 - Unsupported built-in vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR104 - Unsupported built-in vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -24282,23 +27385,23 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR097 - Expected '(' for call to vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR105 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } if (token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR098 - vararg function: " + symbol + - " requires at least one input parameter", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR106 - vararg function: " + symbol + + " requires at least one input parameter", + exprtk_error_location)); return error_node(); } @@ -24316,11 +27419,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR099 - Expected ',' for call to vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR107 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -24337,13 +27440,13 @@ namespace exprtk { if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR100 - Expected '[' as start of string range definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR108 - Expected '[' as start of string range definition", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -24356,7 +27459,7 @@ namespace exprtk if (!parse_range(rp,true)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -24365,19 +27468,32 @@ namespace exprtk if (0 == result) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR101 - Failed to generate string range node", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR109 - Failed to generate string range node", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); rp.free(); } rp.clear(); - return result; + if (result && result->valid()) + { + return result; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR110 - Failed to synthesize node: string_range_node", + exprtk_error_location)); + + free_node(node_allocator_, result); + rp.free(); + return error_node(); } #else inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) @@ -24386,7 +27502,7 @@ namespace exprtk } #endif - inline void parse_pending_string_rangesize(expression_node_ptr& expression) + inline bool parse_pending_string_rangesize(expression_node_ptr& expression) { // Allow no more than 100 range calls, eg: s[][][]...[][] const std::size_t max_rangesize_parses = 100; @@ -24404,6 +27520,61 @@ namespace exprtk { expression = parse_string_range_statement(expression); } + + return (i > 1); + } + + inline void parse_pending_vector_index_operator(expression_node_ptr& expression) + { + if + ( + (0 != expression) && + error_list_.empty() && + is_ivector_node(expression) + ) + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) && + peek_token_is(token_t::e_lsqrbracket) + ) + { + token_is(token_t::e_mul); + token_is(token_t::e_lsqrbracket); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + token_is(token_t::e_lsqrbracket); + } + else if ( + token_is(token_t::e_rbracket,prsrhlpr_t::e_hold) && + peek_token_is(token_t::e_lsqrbracket) + ) + { + token_is(token_t::e_rbracket ); + token_is(token_t::e_lsqrbracket); + } + else + return; + + details::vector_interface* vi = dynamic_cast*>(expression); + + if (vi) + { + details::vector_holder& vec = vi->vec()->vec_holder(); + const std::string vector_name = sem_.get_vector_name(vec.data()); + expression_node_ptr index = parse_vector_index(vector_name); + + if (index) + { + expression = synthesize_vector_element(vector_name, &vec, expression, index); + return; + } + } + + free_node(node_allocator_, expression); + expression = error_node(); + } } template tmp_expression_list; + exprtk_debug(("simplify() - expression_list.size: %d side_effect_list.size(): %d\n", + static_cast(expression_list .size()), + static_cast(side_effect_list.size()))); + bool return_node_present = false; for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) @@ -24439,7 +27614,7 @@ namespace exprtk for (std::size_t j = i + 1; j < expression_list.size(); ++j) { - free_node(node_allocator_,expression_list[j]); + free_node(node_allocator_, expression_list[j]); } return_node_present = true; @@ -24452,7 +27627,7 @@ namespace exprtk !side_effect_list[i] ) { - free_node(node_allocator_,expression_list[i]); + free_node(node_allocator_, expression_list[i]); continue; } else @@ -24493,7 +27668,7 @@ namespace exprtk { token_t::token_type open_bracket = token_t::e_lcrlbracket; token_t::token_type close_bracket = token_t::e_rcrlbracket; - token_t::token_type seperator = token_t::e_eof; + token_t::token_type separator = token_t::e_eof; if (!token_is(open_bracket)) { @@ -24501,16 +27676,16 @@ namespace exprtk { open_bracket = token_t::e_lbracket; close_bracket = token_t::e_rbracket; - seperator = token_t::e_comma; + separator = token_t::e_comma; } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR102 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + - ((!source.empty()) ? std::string(" section of " + source): ""), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR111 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); return error_node(); } @@ -24550,13 +27725,13 @@ namespace exprtk const bool is_next_close = peek_token_is(close_bracket); - if (!token_is(seperator) && is_next_close) + if (!token_is(separator) && is_next_close) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR103 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR112 - Expected '" + lexer::token::seperator_to_str(separator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); return error_node(); } @@ -24574,23 +27749,23 @@ namespace exprtk inline bool parse_range(range_t& rp, const bool skip_lsqr = false) { // Examples of valid ranges: - // 1. [1:5] -> 1..5 - // 2. [ :5] -> 0..5 - // 3. [1: ] -> 1..end - // 4. [x:y] -> x..y where x <= y - // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 - // 6. [ :y] -> 0..y where 0 <= y - // 7. [x: ] -> x..end where x <= end + // 1. [1:5] -> [1,5) + // 2. [ :5] -> [0,5) + // 3. [1: ] -> [1,end) + // 4. [x:y] -> [x,y) where x <= y + // 5. [x+1:y/2] -> [x+1,y/2) where x+1 <= y/2 + // 6. [ :y] -> [0,y) where 0 <= y + // 7. [x: ] -> [x,end) where x <= end rp.clear(); if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR104 - Expected '[' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR113 - Expected '[' for start of range", + exprtk_error_location)); return false; } @@ -24607,11 +27782,11 @@ namespace exprtk if (0 == r0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR105 - Failed parse begin section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR114 - Failed parse begin section of range", + exprtk_error_location)); return false; } @@ -24626,15 +27801,15 @@ namespace exprtk rp.cache.first = rp.n0_c.second; } - free_node(node_allocator_,r0); + free_node(node_allocator_, r0); if (r0_value < T(0)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR106 - Range lower bound less than zero! Constraint: r0 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR115 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); return false; } @@ -24647,11 +27822,11 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR107 - Expected ':' for break in range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR116 - Expected ':' for break in range", + exprtk_error_location)); rp.free(); @@ -24670,11 +27845,11 @@ namespace exprtk if (0 == r1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR108 - Failed parse end section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR117 - Failed parse end section of range", + exprtk_error_location)); rp.free(); @@ -24691,15 +27866,15 @@ namespace exprtk rp.cache.second = rp.n1_c.second; } - free_node(node_allocator_,r1); + free_node(node_allocator_, r1); if (r1_value < T(0)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR109 - Range upper bound less than zero! Constraint: r1 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR118 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); rp.free(); @@ -24714,11 +27889,11 @@ namespace exprtk if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR110 - Expected ']' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR119 - Expected ']' for start of range", + exprtk_error_location)); rp.free(); @@ -24742,11 +27917,11 @@ namespace exprtk if (!rp_result || (r0 > r1)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR111 - Invalid range, Constraint: r0 <= r1", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR120 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); return false; } @@ -24786,11 +27961,11 @@ namespace exprtk if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR112 - Unknown string symbol", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR121 - Unknown string symbol", + exprtk_error_location)); return error_node(); } @@ -24826,7 +28001,7 @@ namespace exprtk if (const_str_node) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); return expression_generator_(T(const_str_node->size())); } @@ -24839,13 +28014,13 @@ namespace exprtk if (!parse_range(rp)) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); return error_node(); } else if (const_str_node) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); result = expression_generator_(const_str_node->ref(),rp); } else @@ -24882,7 +28057,7 @@ namespace exprtk next_token(); next_token(); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return expression_generator_(T(const_str.size())); } @@ -24891,13 +28066,13 @@ namespace exprtk if (!parse_range(rp)) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); rp.free(); return error_node(); } - free_node(node_allocator_,result); + free_node(node_allocator_, result); if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) { @@ -24910,13 +28085,13 @@ namespace exprtk (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR113 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR122 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); rp.free(); @@ -24940,30 +28115,60 @@ namespace exprtk } #endif + inline expression_node_ptr parse_vector_index(const std::string& vector_name = "") + { + expression_node_ptr index_expr = error_node(); + + if (0 == (index_expr = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR123 - Failed to parse index for vector: '" + vector_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR124 - Expected ']' for index of vector: '" + vector_name + "'", + exprtk_error_location)); + + free_node(node_allocator_, index_expr); + + return error_node(); + } + + return index_expr; + } + inline expression_node_ptr parse_vector() { - const std::string symbol = current_token().value; + const std::string vector_name = current_token().value; vector_holder_ptr vec = vector_holder_ptr(0); - const scope_element& se = sem_.get_active_element(symbol); + const scope_element& se = sem_.get_active_element(vector_name); if ( - !details::imatch(se.name, symbol) || + !details::imatch(se.name, vector_name) || (se.depth > state_.scope_depth) || (scope_element::e_vector != se.type) ) { typedef typename symtab_store::vector_context vec_ctxt_t; - vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(symbol); + vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(vector_name); if (0 == vec_ctx.vector_holder) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR114 - Symbol '" + symbol+ " not a vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR125 - Symbol '" + vector_name + " not a vector", + exprtk_error_location)); return error_node(); } @@ -24981,12 +28186,12 @@ namespace exprtk } } else + { vec = se.vec_node; + } assert(0 != vec); - expression_node_ptr index_expr = error_node(); - next_token(); if (!token_is(token_t::e_lsqrbracket)) @@ -24995,31 +28200,28 @@ namespace exprtk } else if (token_is(token_t::e_rsqrbracket)) { - return expression_generator_(T(vec->size())); + return (vec->rebaseable()) ? + node_allocator_.allocate(vec) : + expression_generator_(T(vec->size())); } - else if (0 == (index_expr = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR115 - Failed to parse index for vector: '" + symbol + "'", - exprtk_error_location)); - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR116 - Expected ']' for index of vector: '" + symbol + "'", - exprtk_error_location)); + expression_node_ptr index_expr = parse_vector_index(vector_name); - free_node(node_allocator_,index_expr); + if (index_expr) + { + expression_node_ptr vec_node = node_allocator_.allocate(vec); - return error_node(); + return synthesize_vector_element(vector_name, vec, vec_node, index_expr); } + return error_node(); + } + + inline expression_node_ptr synthesize_vector_element(const std::string& vector_name, + vector_holder_ptr vec, + expression_node_ptr vec_node, + expression_node_ptr index_expr) + { // Perform compile-time range check if (details::is_constant_node(index_expr)) { @@ -25028,20 +28230,21 @@ namespace exprtk if (index >= vec_size) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR117 - Index of " + details::to_str(index) + " out of range for " - "vector '" + symbol + "' of size " + details::to_str(vec_size), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR126 - Index of " + details::to_str(index) + " out of range for " + "vector '" + vector_name + "' of size " + details::to_str(vec_size), + exprtk_error_location)); - free_node(node_allocator_,index_expr); + free_node(node_allocator_, vec_node ); + free_node(node_allocator_, index_expr); return error_node(); } } - return expression_generator_.vector_element(symbol, vec, index_expr); + return expression_generator_.vector_element(vector_name, vec, vec_node, index_expr); } inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) @@ -25060,12 +28263,12 @@ namespace exprtk { if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR118 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR127 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -25085,12 +28288,12 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR119 - Expected ',' for call to vararg function: " - + vararg_function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR128 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); return error_node(); } @@ -25099,37 +28302,37 @@ namespace exprtk } else if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR120 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR129 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } if (arg_list.size() < vararg_function->min_num_args()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR121 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require at least " - + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR130 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } else if (arg_list.size() > vararg_function->max_num_args()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR122 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require no more than " - + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR131 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } @@ -25200,14 +28403,13 @@ namespace exprtk if (1 == error_list.size()) { - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR123 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + function_definition_list_[0].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR132 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } else { @@ -25222,14 +28424,13 @@ namespace exprtk } } - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR124 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + function_definition_list_[max_diff_index].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR133 - Failed parameter type check for function '" + function_name_ + "', " + "Best match: '" + function_definition_list_[max_diff_index].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } return false; @@ -25364,13 +28565,12 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR125 - Invalid parameter sequence of '" + param_seq_list[i] + - "' for function: " + function_name_, - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR134 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); return; } @@ -25380,15 +28580,14 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR126 - Function '" + function_name_ + "' has a parameter sequence conflict between " + - "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + - "pseq_idx[" + details::to_str(i) + "] " + - "param seq: " + param_seq_list[i], - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR135 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + + "pseq_idx[" + details::to_str(i) + "] " + + "param seq: " + param_seq_list[i], + exprtk_error_location)); return; } @@ -25424,11 +28623,11 @@ namespace exprtk if (tc.invalid()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR127 - Type checker instantiation failure for generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR136 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25442,12 +28641,12 @@ namespace exprtk !tc .allow_zero_parameters() ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR128 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR137 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -25474,11 +28673,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR129 - Expected ',' for call to generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR138 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25491,12 +28690,12 @@ namespace exprtk !tc .allow_zero_parameters () ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR130 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR139 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -25508,22 +28707,21 @@ namespace exprtk !tc.verify(param_type_list, param_seq_index) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR131 - Invalid input parameter sequence for call to generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR140 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .generic_function_call(function, arg_list); - else - result = expression_generator_ + result = (tc.paramseq_count() <= 1) ? + expression_generator_ + .generic_function_call(function, arg_list) : + expression_generator_ .generic_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); @@ -25546,12 +28744,12 @@ namespace exprtk !tc .allow_zero_parameters() ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR132 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR141 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return false; } @@ -25578,11 +28776,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR133 - Expected ',' for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR142 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); return false; } @@ -25625,22 +28823,21 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR134 - Invalid input parameter sequence for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR143 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .string_function_call(function, arg_list); - else - result = expression_generator_ + result = (tc.paramseq_count() <= 1) ? + expression_generator_ + .string_function_call(function, arg_list) : + expression_generator_ .string_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); @@ -25677,11 +28874,11 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR135 - Invalid input parameter sequence for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR144 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25708,11 +28905,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR136 - Invalid return type for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR145 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); } sdd.delete_ptr = (0 == result); @@ -25736,11 +28933,11 @@ namespace exprtk if (!p.token_is(token_t::e_lbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR137 - Expected '(' for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR146 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); return error_node(); } @@ -25757,11 +28954,11 @@ namespace exprtk { if (!p.token_is(token_t::e_comma)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR138 - Expected ',' before next parameter of special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR147 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -25770,11 +28967,11 @@ namespace exprtk if (!p.token_is(token_t::e_rbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR139 - Invalid number of parameters for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR148 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -25797,11 +28994,11 @@ namespace exprtk !details::is_digit(sf_name[3]) ) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR140 - Invalid special function[1]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR149 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25811,11 +29008,11 @@ namespace exprtk if (id >= details::e_sffinal) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR141 - Invalid special function[2]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR150 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25843,21 +29040,21 @@ namespace exprtk { if (state_.parsing_break_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR142 - Invoking 'break' within a break call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR151 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); return error_node(); } else if (0 == state_.parsing_loop_stmt_count) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR143 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR152 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25876,23 +29073,23 @@ namespace exprtk { if (0 == (return_expr = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR144 - Failed to parse return expression for 'break' statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR153 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR145 - Expected ']' at the completion of break's return expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR154 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); - free_node(node_allocator_,return_expr); + free_node(node_allocator_, return_expr); return error_node(); } @@ -25904,11 +29101,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR146 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR155 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); } return error_node(); @@ -25918,11 +29115,11 @@ namespace exprtk { if (0 == state_.parsing_loop_stmt_count) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR147 - Invalid use of 'continue', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR156 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25940,123 +29137,222 @@ namespace exprtk inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) { - expression_node_ptr size_expr = error_node(); + expression_node_ptr size_expression_node = error_node(); if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR148 - Expected '[' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR157 - Expected '[' as part of vector size definition", + exprtk_error_location)); return error_node(); } - else if (0 == (size_expr = parse_expression())) + else if (0 == (size_expression_node = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR149 - Failed to determine size of vector '" + vec_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR158 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); return error_node(); } - else if (!is_constant_node(size_expr)) + else if (!is_constant_node(size_expression_node)) { - free_node(node_allocator_,size_expr); + const bool is_rebaseble_vector = + (size_expression_node->type() == details::expression_node::e_vecsize) && + static_cast*>(size_expression_node)->vec_holder()->rebaseable(); - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR150 - Expected a literal number as size of vector '" + vec_name + "'", - exprtk_error_location)); + free_node(node_allocator_, size_expression_node); + + const std::string error_msg = (is_rebaseble_vector) ? + std::string("Rebasable/Resizable vector cannot be used to define the size of vector") : + std::string("Expected a constant literal number as size of vector"); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR159 - " + error_msg + " '" + vec_name + "'", + exprtk_error_location)); return error_node(); } - const T vector_size = size_expr->value(); + const T vector_size = size_expression_node->value(); - free_node(node_allocator_,size_expr); + free_node(node_allocator_, size_expression_node); - const T max_vector_size = T(2000000000.0); + const std::size_t max_vector_size = settings_.max_local_vector_size(); if ( (vector_size <= T(0)) || std::not_equal_to() (T(0),vector_size - details::numeric::trunc(vector_size)) || - (vector_size > max_vector_size) + (static_cast(vector_size) > max_vector_size) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR151 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + - details::to_str(details::numeric::to_int32(vector_size)), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR160 - Invalid vector size. Must be an integer in the " + "range [0," + details::to_str(static_cast(max_vector_size)) + "], size: " + + details::to_str(details::numeric::to_int32(vector_size)), + exprtk_error_location)); return error_node(); } + typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); + + const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); + + scope_element& se = sem_.get_element(vec_name); + + if (se.name == vec_name) + { + if (se.active) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); + + details::set_zero_value(reinterpret_cast(nse.data),vec_size); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + vec_holder = nse.vec_node; + + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name, e_st_local_vector); + std::vector vec_initilizer_list; scoped_vec_delete svd((*this),vec_initilizer_list); bool single_value_initialiser = false; + bool range_value_initialiser = false; bool vec_to_vec_initialiser = false; bool null_initialisation = false; if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR152 - Expected ']' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR163 - Expected ']' as part of vector size definition", + exprtk_error_location)); return error_node(); } - else if (!token_is(token_t::e_eof)) + else if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) { if (!token_is(token_t::e_assign)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR153 - Expected ':=' as part of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR164 - Expected ':=' as part of vector definition", + exprtk_error_location)); return error_node(); } else if (token_is(token_t::e_lsqrbracket)) { - expression_node_ptr initialiser = parse_expression(); + expression_node_ptr initialiser_component = parse_expression(); - if (0 == initialiser) + if (0 == initialiser_component) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR154 - Failed to parse single vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR165 - Failed to parse first component of vector initialiser for vector: " + vec_name, + exprtk_error_location)); return error_node(); } - vec_initilizer_list.push_back(initialiser); + vec_initilizer_list.push_back(initialiser_component); + + if (token_is(token_t::e_colon)) + { + initialiser_component = parse_expression(); + + if (0 == initialiser_component) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR166 - Failed to parse second component of vector initialiser for vector: " + vec_name, + exprtk_error_location)); + + return error_node(); + } + + vec_initilizer_list.push_back(initialiser_component); + } if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR155 - Expected ']' to close single value vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR167 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); return error_node(); } - single_value_initialiser = true; + switch (vec_initilizer_list.size()) + { + case 1 : single_value_initialiser = true; break; + case 2 : range_value_initialiser = true; break; + } } else if (!token_is(token_t::e_lcrlbracket)) { @@ -26066,9 +29362,9 @@ namespace exprtk if (token_t::e_symbol == current_token().type) { // Is it a locally defined vector? - const scope_element& se = sem_.get_active_element(current_token().value); + const scope_element& lcl_se = sem_.get_active_element(current_token().value); - if (scope_element::e_vector == se.type) + if (scope_element::e_vector == lcl_se.type) { if (0 != (initialiser = parse_expression())) vec_initilizer_list.push_back(initialiser); @@ -26094,11 +29390,11 @@ namespace exprtk { if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR156 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR168 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -26114,11 +29410,11 @@ namespace exprtk if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR157 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR169 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -26132,11 +29428,11 @@ namespace exprtk if (!token_is(token_t::e_comma) && is_next_close) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR158 - Expected ',' between vector initialisers", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR170 - Expected ',' between vector initialisers", + exprtk_error_location)); return error_node(); } @@ -26152,99 +29448,118 @@ namespace exprtk !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { - if (!token_is(token_t::e_eof)) + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR159 - Expected ';' at end of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR171 - Expected ';' at end of vector definition", + exprtk_error_location)); return error_node(); } } - if (T(vec_initilizer_list.size()) > vector_size) + if ( + !single_value_initialiser && + !range_value_initialiser && + (T(vec_initilizer_list.size()) > vector_size) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR160 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR172 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); return error_node(); } } - typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - - const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); - - scope_element& se = sem_.get_element(vec_name); + expression_node_ptr result = error_node(); - if (se.name == vec_name) + if ( + (vec_initilizer_list.size() == 1) && + single_value_initialiser + ) { - if (se.active) + if (details::is_constant_node(vec_initilizer_list[0])) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); + // vector_init_zero_value_node var v[10] := [0] + if (T(0) == vec_initilizer_list[0]->value()) + { + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else + { + // vector_init_single_constvalue_node var v[10] := [123] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } } - else if ( - (se.size == vec_size) && - (scope_element::e_vector == se.type) - ) + else { - vec_holder = se.vec_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; + // vector_init_single_value_node var v[10] := [123 + (x / y)] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); } } - - if (0 == vec_holder) + else if ( + (vec_initilizer_list.size() == 2) && + range_value_initialiser + ) { - scope_element nse; - nse.name = vec_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vector; - nse.depth = state_.scope_depth; - nse.size = vec_size; - nse.data = new T[vec_size]; - nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); + bool base_const = details::is_constant_node(vec_initilizer_list[0]); + bool inc_const = details::is_constant_node(vec_initilizer_list[1]); - if (!sem_.add_element(nse)) + if (base_const && inc_const) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - return error_node(); + // vector_init_single_value_node var v[10] := [1 : 3.5] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (base_const && !inc_const) + { + // vector_init_single_value_node var v[10] := [1 : x + y] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (!base_const && inc_const) + { + // vector_init_single_value_node var v[10] := [x + y : 3] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (!base_const && !inc_const) + { + // vector_init_single_value_node var v[10] := [x + y : z / w] + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); } - - vec_holder = nse.vec_node; - - exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", - nse.name.c_str(), - static_cast(nse.size))); } - - state_.activate_side_effect("parse_define_vector_statement()"); - - lodge_symbol(vec_name, e_st_local_vector); - - expression_node_ptr result = error_node(); - - if (null_initialisation) + else if (null_initialisation) result = expression_generator_(T(0.0)); else if (vec_to_vec_initialiser) { @@ -26256,16 +29571,31 @@ namespace exprtk vec_initilizer_list[0]); } else + { result = node_allocator_ - .allocate >( + .allocate >( (*vec_holder)[0], vec_size, vec_initilizer_list, single_value_initialiser); + } - svd.delete_ptr = (0 == result); + svd.delete_ptr = false; - return result; + if (result && result->valid()) + { + return result; + } + + details::free_node(node_allocator_, result); + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR173 - Failed to generate initialisation node for vector: " + vec_name, + exprtk_error_location)); + + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -26279,13 +29609,13 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR163 - Illegal redefinition of local variable: '" + str_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR174 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -26311,13 +29641,13 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR164 - Failed to add new local string variable '" + str_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR175 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); sem_.free_element(nse); @@ -26326,7 +29656,7 @@ namespace exprtk str_node = nse.str_node; - exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n", nse.name.c_str())); } lodge_symbol(str_name, e_st_local_string); @@ -26357,11 +29687,11 @@ namespace exprtk { if (settings_.vardef_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR165 - Illegal variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR176 - Illegal variable definition", + exprtk_error_location)); return error_node(); } @@ -26378,41 +29708,41 @@ namespace exprtk if (!token_is(token_t::e_symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR166 - Expected a symbol for variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR177 - Expected a symbol for variable definition", + exprtk_error_location)); return error_node(); } else if (details::is_reserved_symbol(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR167 - Illegal redefinition of reserved keyword: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR178 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); return error_node(); } else if (symtab_store_.symbol_exists(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR168 - Illegal redefinition of variable '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR179 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); return error_node(); } else if (local_variable_is_shadowed(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR169 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR180 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -26428,11 +29758,11 @@ namespace exprtk { if (0 == (initialisation_expression = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR170 - Failed to parse initialisation expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR181 - Failed to parse initialisation expression for variable '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -26446,13 +29776,13 @@ namespace exprtk { if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR171 - Expected ';' after variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR182 - Expected ';' after variable '" + var_name + "' definition", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -26474,11 +29804,11 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR183 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26506,11 +29836,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR184 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26521,7 +29851,7 @@ namespace exprtk var_node = nse.var_node; - exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n", nse.name.c_str())); } state_.activate_side_effect("parse_define_var_statement()"); @@ -26536,6 +29866,174 @@ namespace exprtk return expression_generator_(details::e_assign,branch); } + inline expression_node_ptr parse_define_constvar_statement() + { + if (settings_.vardef_disabled()) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR185 - Illegal const variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is("const")) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR186 - Expected 'const' keyword for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is("var")) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR187 - Expected 'var' keyword for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + + const std::string var_name = current_token().value; + + expression_node_ptr initialisation_expression = error_node(); + + if (!token_is(token_t::e_symbol)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR188 - Expected a symbol for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (details::is_reserved_symbol(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR189 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR190 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR191 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR192 - Failed to parse initialisation expression for const-variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!details::is_literal_node(initialisation_expression)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR193 - initialisation expression for const-variable: '" + var_name + "' must be a constant/literal", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + return error_node(); + } + } + + const T init_value = initialisation_expression->value(); + + free_node(node_allocator_, initialisation_expression); + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR194 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (scope_element::e_literal == se.type) + { + var_node = se.var_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_literal; + nse.depth = state_.scope_depth; + nse.data = 0; + nse.var_node = node_allocator_.allocate(init_value); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR195 - Failed to add new local const-variable '" + var_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + var_node = nse.var_node; + + exprtk_debug(("parse_define_constvar_statement() - INFO - Added new local const-variable: %s\n", nse.name.c_str())); + } + + state_.activate_side_effect("parse_define_constvar_statement()"); + + lodge_symbol(var_name, e_st_local_variable); + + return expression_generator_(var_node->value()); + } + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) { if ( @@ -26543,21 +30041,21 @@ namespace exprtk !token_is(token_t::e_rcrlbracket) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR174 - Expected a '{}' for uninitialised var definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR196 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR175 - Expected ';' after uninitialised variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR197 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); return error_node(); } @@ -26570,11 +30068,11 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR176 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR198 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -26600,11 +30098,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR177 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR199 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -26633,11 +30131,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR178 - Expected '(' at start of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR200 - Expected '(' at start of swap statement", + exprtk_error_location)); return error_node(); } @@ -26652,11 +30150,11 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR179 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR201 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); return error_node(); } @@ -26664,11 +30162,11 @@ namespace exprtk { if (0 == (variable0 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR180 - First parameter to swap is an invalid vector element: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR202 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -26697,11 +30195,11 @@ namespace exprtk if (0 == variable0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR181 - First parameter to swap is an invalid variable: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR203 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -26711,15 +30209,15 @@ namespace exprtk if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR182 - Expected ',' between parameters to swap", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR204 - Expected ',' between parameters to swap", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -26729,15 +30227,15 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR183 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR205 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -26746,15 +30244,15 @@ namespace exprtk { if (0 == (variable1 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR184 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR206 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -26784,15 +30282,15 @@ namespace exprtk if (0 == variable1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR185 - Second parameter to swap is an invalid variable: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR207 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -26803,20 +30301,20 @@ namespace exprtk if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR186 - Expected ')' at end of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR208 - Expected ')' at end of swap statement", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } if (variable1_generated) { - free_node(node_allocator_,variable1); + free_node(node_allocator_, variable1); } return error_node(); @@ -26838,12 +30336,12 @@ namespace exprtk if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } if (variable1_generated) { - free_node(node_allocator_,variable1); + free_node(node_allocator_, variable1); } } else @@ -26860,11 +30358,11 @@ namespace exprtk { if (state_.parsing_return_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR187 - Return call within a return call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR209 - Return call within a return call is not allowed", + exprtk_error_location)); return error_node(); } @@ -26884,11 +30382,11 @@ namespace exprtk if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR188 - Expected '[' at start of return statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR210 - Expected '[' at start of return statement", + exprtk_error_location)); return error_node(); } @@ -26907,11 +30405,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR189 - Expected ',' between values during call to return", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR211 - Expected ',' between values during call to return", + exprtk_error_location)); return error_node(); } @@ -26919,11 +30417,11 @@ namespace exprtk } else if (settings_.zero_return_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR190 - Zero parameter return statement not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR212 - Zero parameter return statement not allowed", + exprtk_error_location)); return error_node(); } @@ -26934,11 +30432,11 @@ namespace exprtk { if (!arg_list.empty()) { - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR191 - Invalid ']' found during return call", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR213 - Invalid ']' found during return call", + exprtk_error_location)); return error_node(); } @@ -26977,6 +30475,194 @@ namespace exprtk } #endif + inline expression_node_ptr parse_assert_statement() + { + assert(details::imatch(current_token().value, "assert")); + + if (state_.parsing_assert_stmt) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR214 - Assert statement within an assert statement is not allowed", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_assert_stmt); + + next_token(); + + std::vector assert_arg_list(3, error_node()); + scoped_vec_delete sdd((*this), assert_arg_list); + + expression_node_ptr& assert_condition = assert_arg_list[0]; + expression_node_ptr& assert_message = assert_arg_list[1]; + expression_node_ptr& assert_id = assert_arg_list[2]; + + if (!token_is(token_t::e_lbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR215 - Expected '(' at start of assert statement", + exprtk_error_location)); + + return error_node(); + } + + const token_t start_token = current_token(); + + // Parse the assert condition + if (0 == (assert_condition = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR216 - Failed to parse condition for assert statement", + exprtk_error_location)); + + return error_node(); + } + + const token_t end_token = current_token(); + + if (!token_is(token_t::e_rbracket)) + { + if (!token_is(token_t::e_comma)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR217 - Expected ',' between condition and message for assert statement", + exprtk_error_location)); + + return error_node(); + } + // Parse the assert message + else if ( + (0 == (assert_message = parse_expression())) || + !details::is_generally_string_node(assert_message) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR218 - " + + (assert_message ? + std::string("Expected string for assert message") : + std::string("Failed to parse message for assert statement")), + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + if (!token_is(token_t::e_comma)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR219 - Expected ',' between message and ID for assert statement", + exprtk_error_location)); + + return error_node(); + } + // Parse assert ID + else if ( + (0 == (assert_id = parse_expression())) || + !details::is_const_string_node(assert_id) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR220 - " + + (assert_id ? + std::string("Expected literal string for assert ID") : + std::string("Failed to parse string for assert ID")), + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR221 - Expected ')' at start of assert statement", + exprtk_error_location)); + + return error_node(); + } + } + } + + exprtk::assert_check::assert_context context; + context.condition = lexer().substr(start_token.position, end_token.position); + context.offet = start_token.position; + + if (0 == assert_check_) + { + exprtk_debug(("parse_assert_statement() - assert functionality is disabled. assert condition: %s\n", + context.condition.c_str())); + + return new details::null_node(); + } + + #ifndef exprtk_disable_string_capabilities + if (assert_message && details::is_const_string_node(assert_message)) + { + context.message = dynamic_cast*>(assert_message)->str(); + } + + if (assert_id && details::is_const_string_node(assert_id)) + { + context.id = dynamic_cast*>(assert_id)->str(); + + if (assert_ids_.end() != assert_ids_.find(context.id)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR222 - Duplicate assert ID: " + context.id, + exprtk_error_location)); + + return error_node(); + } + + assert_ids_.insert(context.id); + free_node(node_allocator_, assert_id); + } + #endif + + expression_node_ptr result_node = + expression_generator_.assert_call( + assert_condition, + assert_message, + context); + + exprtk_debug(("parse_assert_statement() - assert condition: [%s]\n", context.condition.c_str() )); + exprtk_debug(("parse_assert_statement() - assert message: [%s]\n", context.message .c_str() )); + exprtk_debug(("parse_assert_statement() - assert id: [%s]\n", context.id .c_str() )); + exprtk_debug(("parse_assert_statement() - assert offset: [%d]\n", static_cast(context.offet))); + + if (0 == result_node) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR223 - Failed to synthesize assert", + exprtk_error_location)); + + return error_node(); + } + + sdd.delete_ptr = false; + return result_node; + } + inline bool post_variable_process(const std::string& symbol) { if ( @@ -26987,11 +30673,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR192 - Invalid sequence of variable '" + symbol + "' and bracket", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR224 - Invalid sequence of variable '" + symbol + "' and bracket", + exprtk_error_location)); return false; } @@ -27009,23 +30695,26 @@ namespace exprtk if (details::is_generally_string_node(branch)) return true; + if (details::is_ivector_node(branch)) + return true; + const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; switch (token) { - case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; - case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; - case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; default : return true; @@ -27035,11 +30724,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR193 - Invalid sequence of brackets", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR225 - Invalid sequence of brackets", + exprtk_error_location)); return false; } @@ -27122,7 +30811,10 @@ namespace exprtk if (se.active && details::imatch(se.name, symbol)) { - if (scope_element::e_variable == se.type) + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_literal == se.type) + ) { se.active = true; lodge_symbol(symbol, e_st_local_variable); @@ -27132,7 +30824,9 @@ namespace exprtk next_token(); - return se.var_node; + return (scope_element::e_variable == se.type) ? + se.var_node : + expression_generator_(se.var_node->value()); } else if (scope_element::e_vector == se.type) { @@ -27170,11 +30864,11 @@ namespace exprtk return func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR194 - Failed to generate node for function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR226 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27196,11 +30890,11 @@ namespace exprtk return vararg_func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR195 - Failed to generate node for vararg function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR227 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27222,11 +30916,11 @@ namespace exprtk return genericfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR196 - Failed to generate node for generic function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR228 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27249,11 +30943,11 @@ namespace exprtk return stringfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR197 - Failed to generate node for string function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR229 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27275,11 +30969,11 @@ namespace exprtk return overloadfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR198 - Failed to generate node for overload function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR230 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27301,11 +30995,11 @@ namespace exprtk !details::is_base_function(symbol) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR199 - Invalid use of reserved symbol '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR231 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27332,11 +31026,13 @@ namespace exprtk switch (usr_symbol_type) { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); - break; + case unknown_symbol_resolver::e_usr_variable_type : + create_result = symtab.create_variable(symbol, default_value); + break; - case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); - break; + case unknown_symbol_resolver::e_usr_constant_type : + create_result = symtab.add_constant(symbol, default_value); + break; default : create_result = false; } @@ -27364,12 +31060,12 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR200 - Failed to create variable: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR232 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) @@ -27384,27 +31080,51 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR201 - Failed to resolve symbol: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR233 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } return error_node(); } } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR202 - Undefined symbol: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR234 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } + inline expression_node_ptr check_block_statement_closure(expression_node_ptr expression) + { + if ( + expression && + ( + (current_token().type == token_t::e_symbol) || + (current_token().type == token_t::e_number) + ) + ) + { + free_node(node_allocator_, expression); + + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR235 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + return error_node(); + } + + return expression; + } + inline expression_node_ptr parse_symbol() { static const std::string symbol_if = "if" ; @@ -27416,9 +31136,11 @@ namespace exprtk static const std::string symbol_break = "break" ; static const std::string symbol_continue = "continue"; static const std::string symbol_var = "var" ; + static const std::string symbol_const = "const" ; static const std::string symbol_swap = "swap" ; static const std::string symbol_return = "return" ; static const std::string symbol_not = "not" ; + static const std::string symbol_assert = "assert" ; const std::string symbol = current_token().value; @@ -27446,28 +31168,28 @@ namespace exprtk settings_.control_struct_enabled(symbol) ) { - return parse_while_loop(); + return check_block_statement_closure(parse_while_loop()); } else if ( details::imatch(symbol, symbol_repeat) && settings_.control_struct_enabled(symbol) ) { - return parse_repeat_until_loop(); + return check_block_statement_closure(parse_repeat_until_loop()); } else if ( details::imatch(symbol, symbol_for) && settings_.control_struct_enabled(symbol) ) { - return parse_for_loop(); + return check_block_statement_closure(parse_for_loop()); } else if ( details::imatch(symbol, symbol_switch) && settings_.control_struct_enabled(symbol) ) { - return parse_switch_statement(); + return check_block_statement_closure(parse_switch_statement()); } else if (details::is_valid_sf_symbol(symbol)) { @@ -27491,6 +31213,10 @@ namespace exprtk { return parse_define_var_statement(); } + else if (details::imatch(symbol, symbol_const)) + { + return parse_define_constvar_statement(); + } else if (details::imatch(symbol, symbol_swap)) { return parse_swap_statement(); @@ -27501,20 +31227,25 @@ namespace exprtk settings_.control_struct_enabled(symbol) ) { - return parse_return_statement(); + return check_block_statement_closure(parse_return_statement()); } #endif + else if (details::imatch(symbol, symbol_assert)) + { + return parse_assert_statement(); + } else if (symtab_store_.valid() || !sem_.empty()) { return parse_symtab_symbol(); } else { - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR203 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR236 - Unknown variable or function encountered. Symbol table(s) " + "is either invalid or does not contain symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27541,11 +31272,11 @@ namespace exprtk if (0 == literal_exp) { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR204 - Failed generate node for scalar: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR237 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } @@ -27555,11 +31286,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR205 - Failed to convert '" + current_token().value + "' to a number", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR238 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); return error_node(); } @@ -27579,25 +31310,32 @@ namespace exprtk next_token(); if (0 == (branch = parse_expression())) + { return error_node(); - else if (!token_is(token_t::e_rbracket)) + } + + token_is(token_t::e_eof); + + if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR206 - Expected ')' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR239 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lbracket,branch)) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } + + parse_pending_vector_index_operator(branch); } else if (token_t::e_lsqrbracket == current_token().type) { @@ -27607,19 +31345,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR207 - Expected ']' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR240 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27632,19 +31370,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR208 - Expected '}' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR241 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27666,7 +31404,7 @@ namespace exprtk if (0 == result) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27681,21 +31419,21 @@ namespace exprtk } else if (token_t::e_eof == current_token().type) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR209 - Premature end of expression[1]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR242 - Premature end of expression[1]", + exprtk_error_location)); return error_node(); } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR210 - Premature end of expression[2]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR243 - Premature end of expression[2]", + exprtk_error_location)); return error_node(); } @@ -27796,6 +31534,8 @@ namespace exprtk register_synthezier(synthesize_covocov_expression4) register_synthezier(synthesize_vocovoc_expression4) register_synthezier(synthesize_covovoc_expression4) + + #undef register_synthezier #endif } @@ -27848,7 +31588,7 @@ namespace exprtk { typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); - if ((*binary_op_map_).end() == bop_itr) + if (binary_op_map_->end() == bop_itr) return false; bop = bop_itr->second; @@ -28260,13 +32000,20 @@ namespace exprtk if (details::is_string_node(branch[0])) return !b1_is_genstring; + else if (details::is_literal_node(branch[0])) + return true; else return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node (branch[0]) && - !details::is_rebasevector_elem_node (branch[0]) && - !details::is_rebasevector_celem_node(branch[0]) && - !details::is_vector_node (branch[0]) + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node (branch[0]) && + !details::is_vector_celem_node (branch[0]) && + !details::is_vector_elem_rtc_node (branch[0]) && + !details::is_vector_celem_rtc_node (branch[0]) && + !details::is_rebasevector_elem_node (branch[0]) && + !details::is_rebasevector_celem_node (branch[0]) && + !details::is_rebasevector_elem_rtc_node (branch[0]) && + !details::is_rebasevector_celem_rtc_node(branch[0]) && + !details::is_vector_node (branch[0]) ) || b1_is_genstring; } @@ -28421,18 +32168,42 @@ namespace exprtk { if ((0 == branch[0]) || (0 == branch[1])) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR244 - Invalid branches received for operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_string_op(operation,branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR245 - Invalid branch pair for string operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_assignment_op(operation,branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR246 - Invalid branch pair for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_break_continue_op(branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR247 - Invalid branch pair for break/continue operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (details::e_assign == operation) @@ -28551,10 +32322,22 @@ namespace exprtk { details::free_all_nodes(*node_allocator_,branch); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR248 - Invalid branches operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_string_op(operation, branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR249 - Invalid branches for string operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_string_operation(operation, branch)) @@ -28601,6 +32384,16 @@ namespace exprtk details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR250 - Invalid " + invalid_branches + " for conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28626,14 +32419,34 @@ namespace exprtk return node_allocator_->allocate >(); } } - else if ((0 != consequent) && (0 != alternative)) + + expression_node_ptr result = error_node(); + std::string node_name = "Unknown!"; + + if ((0 != consequent) && (0 != alternative)) { - return node_allocator_-> - allocate(condition, consequent, alternative); + result = node_allocator_->allocate(condition, consequent, alternative); + node_name = "conditional_node_t"; } else - return node_allocator_-> - allocate(condition, consequent); + { + result = node_allocator_->allocate(condition, consequent); + node_name = "cons_conditional_node_t"; + } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR251 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -28647,6 +32460,16 @@ namespace exprtk details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR252 - Invalid " + invalid_branches + " for string conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28674,10 +32497,25 @@ namespace exprtk } } else if ((0 != consequent) && (0 != alternative)) - return node_allocator_-> - allocate(condition, consequent, alternative); - else - return error_node(); + { + expression_node_ptr result = + node_allocator_->allocate(condition, consequent, alternative); + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR253 - Failed to synthesize node: conditional_string_node_t", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + } + + return error_node(); } #else inline expression_node_ptr conditional_string(expression_node_ptr, @@ -28698,6 +32536,16 @@ namespace exprtk details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR254 - Invalid " + invalid_branches + " for vector conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28746,16 +32594,34 @@ namespace exprtk return loop_runtime_check_ptr(0); } + inline vector_access_runtime_check_ptr get_vector_access_runtime_check() const + { + return parser_->vector_access_runtime_check_; + } + inline expression_node_ptr while_loop(expression_node_ptr& condition, expression_node_ptr& branch, const bool break_continue_present = false) const { - if (!break_continue_present && details::is_constant_node(condition)) + if ( + !break_continue_present && + !parser_->state_.return_stmt_present && + details::is_constant_node(condition) + ) { expression_node_ptr result = error_node(); if (details::is_true(condition)) + { // Infinite loops are not allowed. + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR255 - Infinite loop condition without 'break' or 'return' not allowed in while-loops", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate >(); @@ -28857,13 +32723,26 @@ namespace exprtk expression_node_ptr& loop_body, bool break_continue_present = false) const { - if (!break_continue_present && details::is_constant_node(condition)) + if ( + !break_continue_present && + !parser_->state_.return_stmt_present && + details::is_constant_node(condition) + ) { expression_node_ptr result = error_node(); if (details::is_true(condition)) + { // Infinite loops are not allowed. + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR256 - Infinite loop condition without 'break' or 'return' not allowed in for-loop", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate >(); @@ -28890,19 +32769,19 @@ namespace exprtk if (rtc) return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body, - rtc + initialiser, + condition, + incrementor, + loop_body, + rtc ); else return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body + initialiser, + condition, + incrementor, + loop_body ); } #ifndef exprtk_disable_break_continue @@ -28911,19 +32790,19 @@ namespace exprtk if (rtc) return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body, - rtc + initialiser, + condition, + incrementor, + loop_body, + rtc ); else return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body + initialiser, + condition, + incrementor, + loop_body ); } #else @@ -28986,8 +32865,8 @@ namespace exprtk if (0 == result) { - T zero = T(0); - result = node_allocator_->allocate(zero); + const T zero = T(0); + result = node_allocator_->allocate(zero); } for (std::size_t i = 0; i < arg_list.size(); ++i) @@ -29161,6 +33040,28 @@ namespace exprtk return node_allocator_->allocate >(arg_list); } + inline expression_node_ptr assert_call(expression_node_ptr& assert_condition, + expression_node_ptr& assert_message, + const assert_check::assert_context& context) + { + typedef details::assert_node alloc_type; + + expression_node_ptr result = node_allocator_->allocate_rrrr + (assert_condition, assert_message, parser_->assert_check_, context); + + if (result && result->valid()) + { + parser_->state_.activate_side_effect("assert_call()"); + return result; + } + + details::free_node(*node_allocator_, result ); + details::free_node(*node_allocator_, assert_condition); + details::free_node(*node_allocator_, assert_message ); + + return error_node(); + } + #define unary_opr_switch_statements \ case_stmt(details::e_abs , details::abs_op ) \ case_stmt(details::e_acos , details::acos_op ) \ @@ -29280,6 +33181,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -29383,6 +33286,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -29503,7 +33408,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, + Sequence& arg_list) { switch (operation) { @@ -29526,7 +33432,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr vectorize_func(const details::operator_type& operation, + Sequence& arg_list) { if (1 == arg_list.size()) { @@ -29551,7 +33458,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr vararg_function(const details::operator_type& operation, + Sequence& arg_list) { if (!all_nodes_valid(arg_list)) { @@ -29561,9 +33469,9 @@ namespace exprtk } else if (is_constant_foldable(arg_list)) return const_optimise_varargfunc(operation,arg_list); - else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) + else if ((1 == arg_list.size()) && details::is_ivector_node(arg_list[0])) return vectorize_func(operation,arg_list); - else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + else if ((1 == arg_list.size()) && special_one_parameter_vararg(operation)) return arg_list[0]; else if (all_nodes_variables(arg_list)) return varnode_optimise_varargfunc(operation,arg_list); @@ -29571,17 +33479,32 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities if (details::e_smulti == operation) { - return node_allocator_-> + expression_node_ptr result = node_allocator_-> allocate > >(arg_list); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR257 - Failed to synthesize node: str_vararg_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); } else #endif { + expression_node_ptr result = error_node(); + switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ allocate > >(arg_list); \ + break; \ case_stmt(details::e_sum , details::vararg_add_op ) case_stmt(details::e_prod , details::vararg_mul_op ) @@ -29594,7 +33517,22 @@ namespace exprtk #undef case_stmt default : return error_node(); } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR258 - Failed to synthesize node: vararg_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); } + + return error_node(); } template @@ -29635,7 +33573,19 @@ namespace exprtk return error_node(); } - return result; + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR259 - Failed to synthesize node: function_N_node_t", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } } @@ -29672,7 +33622,19 @@ namespace exprtk parser_->state_.activate_side_effect("vararg_function_call()"); - return result; + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR260 - Failed to synthesize node: vararg_function_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } inline expression_node_ptr generic_function_call(igeneric_function_t* gf, @@ -29691,14 +33653,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate(arg_list,gf); + node_name = "generic_function_node"; + } else + { result = node_allocator_->allocate(gf, param_seq_index, arg_list); + node_name = "multimode_genfunction_node"; + } alloc_type1* genfunc_node_ptr = static_cast(result); + assert(genfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -29716,9 +33687,20 @@ namespace exprtk } else if (genfunc_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("generic_function_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("generic_function_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR261 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29746,14 +33728,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate(gf,arg_list); + node_name = "string_function_node"; + } else + { result = node_allocator_->allocate(gf, param_seq_index, arg_list); + node_name = "multimode_strfunction_node"; + } alloc_type1* strfunc_node_ptr = static_cast(result); + assert(strfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -29770,9 +33761,20 @@ namespace exprtk } else if (strfunc_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("string_function_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("string_function_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR262 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29800,11 +33802,24 @@ namespace exprtk alloc_type* return_node_ptr = static_cast(result); + assert(return_node_ptr); + if (return_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("return_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("return_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR263 - Failed to synthesize node: return_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29842,28 +33857,93 @@ namespace exprtk } #endif - inline expression_node_ptr vector_element(const std::string& symbol, - vector_holder_ptr vector_base, + inline expression_node_ptr vector_element(const std::string& symbol, + vector_holder_ptr vector_base, + expression_node_ptr vec_node, expression_node_ptr index) { expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (details::is_constant_node(index)) { - std::size_t i = static_cast(details::numeric::to_int64(index->value())); + const std::size_t vec_index = static_cast(details::numeric::to_int64(index->value())); details::free_node(*node_allocator_,index); + if (vec_index >= vector_base->size()) + { + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR264 - Index of " + details::to_str(vec_index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vector_base->size()), + exprtk_error_location)); + + details::free_node(*node_allocator_,vec_node); + + return error_node(); + } + if (vector_base->rebaseable()) { - return node_allocator_->allocate(i,vector_base); + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); + + result = (rtc) ? + node_allocator_->allocate(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate(vec_node, vec_index, vector_base ) ; + + node_name = (rtc) ? + "rebasevector_elem_rtc_node_t" : + "rebasevector_elem_node_t" ; + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR265 - Failed to synthesize node: " + node_name + " for vector: " + symbol, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + } + else if (details::is_ivector_node(vec_node) && !details::is_vector_node(vec_node)) + { + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); + + result = (rtc) ? + node_allocator_->allocate(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate(vec_node, vec_index, vector_base ) ; + + node_name = (rtc) ? + "vector_elem_rtc_node_t" : + "vector_elem_node_t" ; + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR266 - Failed to synthesize node: " + node_name + " for vector: " + symbol, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } - const scope_element& se = parser_->sem_.get_element(symbol,i); + const scope_element& se = parser_->sem_.get_element(symbol,vec_index); - if (se.index == i) + if (se.index == vec_index) { result = se.var_node; + details::free_node(*node_allocator_,vec_node); } else { @@ -29872,10 +33952,10 @@ namespace exprtk nse.active = true; nse.ref_count = 1; nse.type = scope_element::e_vecelem; - nse.index = i; + nse.index = vec_index; nse.depth = parser_->state_.scope_depth; nse.data = 0; - nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); + nse.var_node = node_allocator_->allocate((*(*vector_base)[vec_index])); if (!parser_->sem_.add_element(nse)) { @@ -29886,19 +33966,55 @@ namespace exprtk result = error_node(); } - exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + details::free_node(*node_allocator_,vec_node); + + exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n", nse.name.c_str())); parser_->state_.activate_side_effect("vector_element()"); result = nse.var_node; + node_name = "variable_node_t"; } } - else if (vector_base->rebaseable()) - result = node_allocator_->allocate(index,vector_base); else - result = node_allocator_->allocate(index,vector_base); + { + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); - return result; + if (vector_base->rebaseable()) + { + result = (rtc) ? + node_allocator_->allocate(vec_node, index, vector_base, rtc) : + node_allocator_->allocate(vec_node, index, vector_base ) ; + + node_name = (rtc) ? + "rebasevector_elem_rtc_node_t" : + "rebasevector_elem_node_t" ; + } + else + { + result = rtc ? + node_allocator_->allocate(vec_node, index, vector_base, rtc) : + node_allocator_->allocate(vec_node, index, vector_base ) ; + + node_name = (rtc) ? + "vector_elem_rtc_node_t" : + "vector_elem_node_t" ; + } + } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR267 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } private: @@ -29995,12 +34111,27 @@ namespace exprtk case details::expression_node::e_vecelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_veccelem: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_vecelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_veccelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbvecelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbvecelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbveccelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbveccelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_vector: return reinterpret_cast(static_cast(node)->vec_holder().data()); @@ -30032,11 +34163,11 @@ namespace exprtk if (parser_->immutable_symtok_map_.end() != itr) { token_t& token = itr->second; - parser_->set_error( - parser_error::make_error(parser_error::e_parser, - token, - "ERR211 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", - exprtk_error_location)); + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token, + "ERR268 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", + exprtk_error_location)); } else parser_->set_synthesis_error("Unable to assign symbol is immutable."); @@ -30058,16 +34189,26 @@ namespace exprtk lodge_assignment(e_st_variable,branch[0]); return synthesize_expression(operation,branch); } - else if (details::is_vector_elem_node(branch[0])) + else if (details::is_vector_elem_node(branch[0]) || details::is_vector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } + else if (details::is_vector_elem_rtc_node(branch[0]) || details::is_vector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + return synthesize_expression(operation, branch); + } else if (details::is_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } + else if (details::is_rebasevector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + return synthesize_expression(operation, branch); + } else if (details::is_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); @@ -30094,9 +34235,23 @@ namespace exprtk else return synthesize_expression(operation, branch); } + else if (details::is_literal_node(branch[0])) + { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR269 - Cannot assign value to const variable", + exprtk_error_location)); + + return error_node(); + } else { - parser_->set_synthesis_error("Invalid assignment operation.[1]"); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR270 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); return error_node(); } @@ -30110,6 +34265,9 @@ namespace exprtk return error_node(); } + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; + if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); @@ -30117,9 +34275,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30137,9 +34297,55 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_elem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_elem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_celem_op_rtc_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30157,9 +34363,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_elem_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30177,9 +34385,55 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_celem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_elem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_celem_op_rtc_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30199,9 +34453,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_celem_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30217,9 +34473,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30241,15 +34499,34 @@ namespace exprtk lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation,branch); + result = synthesize_expression(operation,branch); + node_name = "assignment_string_node"; } #endif else { - parser_->set_synthesis_error("Invalid assignment operation[2]"); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR271 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); return error_node(); } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR272 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, @@ -30273,14 +34550,19 @@ namespace exprtk case_stmt(details::e_xor , details::xor_op ) \ case_stmt(details::e_xnor , details::xnor_op ) \ + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; + if (is_b0_ivec && is_b1_ivec) { switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30292,9 +34574,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30306,9 +34590,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_valvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30318,6 +34604,20 @@ namespace exprtk else return error_node(); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR273 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef batch_eqineq_logic_case } @@ -30334,14 +34634,19 @@ namespace exprtk case_stmt(details::e_div , details::div_op) \ case_stmt(details::e_mod , details::mod_op) \ + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; + if (is_b0_ivec && is_b1_ivec) { switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -30354,9 +34659,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(b0ivec,!b1ivec)"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -30369,9 +34676,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(!b0ivec,b1ivec)"; \ + break; \ vector_ops #undef case_stmt @@ -30381,6 +34690,20 @@ namespace exprtk else return error_node(); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR274 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef vector_ops } @@ -30398,6 +34721,7 @@ namespace exprtk #endif expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (v0_is_ivar && v1_is_ivar) { @@ -30411,36 +34735,57 @@ namespace exprtk (0 != (v1 = dynamic_cast(branch[1]))) ) { - result = node_allocator_->allocate >(v0,v1); + result = node_allocator_->allocate >(v0,v1); + node_name = "swap_node"; } else - result = node_allocator_->allocate >(branch[0],branch[1]); + { + result = node_allocator_->allocate >(branch[0],branch[1]); + node_name = "swap_generic_node"; + } } else if (v0_is_ivec && v1_is_ivec) { - result = node_allocator_->allocate >(branch[0],branch[1]); + result = node_allocator_->allocate >(branch[0],branch[1]); + node_name = "swap_vecvec_node"; } #ifndef exprtk_disable_string_capabilities else if (v0_is_str && v1_is_str) { if (is_string_node(branch[0]) && is_string_node(branch[1])) + { result = node_allocator_->allocate > (branch[0], branch[1]); + node_name = "swap_string_node"; + } else + { result = node_allocator_->allocate > (branch[0], branch[1]); + node_name = "swap_genstrings_node"; + } } #endif else { parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); - return error_node(); } - parser_->state_.activate_side_effect("synthesize_swap_expression()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("synthesize_swap_expression()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR275 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_sc_andor @@ -30596,7 +34941,7 @@ namespace exprtk else if (not_recipricol) return cardinal_pow_optimisation_impl(branch[0],p); else - return cardinal_pow_optimisation_impl(branch[0],p); + return cardinal_pow_optimisation_impl(branch[0],p); } #else inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) @@ -31969,9 +36314,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -32034,9 +36379,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32100,9 +36445,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -32165,9 +36510,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32230,9 +36575,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -32295,9 +36640,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32360,9 +36705,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -32426,9 +36771,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32545,9 +36890,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -32664,9 +37009,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32795,9 +37140,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -32922,9 +37267,9 @@ namespace exprtk const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -33057,10 +37402,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33146,10 +37491,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33235,10 +37580,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33324,10 +37669,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33413,10 +37758,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33607,10 +37952,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33851,10 +38196,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34045,10 +38390,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34238,10 +38583,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34298,10 +38643,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34358,10 +38703,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34418,10 +38763,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34478,10 +38823,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34539,10 +38884,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34600,10 +38945,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34660,10 +39005,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34720,10 +39065,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34780,10 +39125,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -34840,10 +39185,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34900,10 +39245,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34960,10 +39305,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35020,10 +39365,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35081,10 +39426,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35142,10 +39487,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35202,10 +39547,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35263,10 +39608,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -35344,10 +39689,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35405,10 +39750,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35465,10 +39810,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35525,10 +39870,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35585,10 +39930,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35645,10 +39990,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35706,10 +40051,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35767,10 +40112,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35827,10 +40172,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35887,10 +40232,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35948,10 +40293,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36008,10 +40353,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36067,10 +40412,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36127,10 +40472,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36187,10 +40532,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36248,10 +40593,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36309,10 +40654,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -36737,6 +41082,8 @@ namespace exprtk default : return error_node(); } } + + #undef string_opr_switch_statements #endif #ifndef exprtk_disable_string_capabilities @@ -37070,11 +41417,22 @@ namespace exprtk return node_allocator_->allocate(v); } - else + + if (expression_point && expression_point->valid()) + { return expression_point; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR276 - Failed to synthesize node: NodeType", + exprtk_error_location)); + + details::free_node(*node_allocator_, expression_point); } - else - return error_node(); + + return error_node(); } template @@ -37154,8 +41512,11 @@ namespace exprtk { scope_element& se = sem_.get_element(i); + exprtk_debug(("register_local_vars() - se[%s]\n", se.name.c_str())); + if ( (scope_element::e_variable == se.type) || + (scope_element::e_literal == se.type) || (scope_element::e_vecelem == se.type) ) { @@ -37428,6 +41789,7 @@ namespace exprtk sf4_map_t sf4_map_; std::string synthesis_error_; scope_element_manager sem_; + std::vector current_state_stack_; immutable_memory_map_t immutable_memory_map_; immutable_symtok_map_t immutable_symtok_map_; @@ -37443,7 +41805,11 @@ namespace exprtk lexer::helper::sequence_validator sequence_validator_; lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; - loop_runtime_check_ptr loop_runtime_check_; + loop_runtime_check_ptr loop_runtime_check_; + vector_access_runtime_check_ptr vector_access_runtime_check_; + compilation_check_ptr compilation_check_ptr_; + assert_check_ptr assert_check_; + std::set assert_ids_; template friend void details::disable_type_checking(ParserType& p); @@ -37460,17 +41826,19 @@ namespace exprtk typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; typedef typename parser_t::unknown_symbol_resolver usr_t; - struct resolve_as_vector : public parser_t::unknown_symbol_resolver + struct resolve_as_vector : public usr_t { typedef exprtk::parser parser_t; + using usr_t::process; + resolve_as_vector() : usr_t(usr_t::e_usrmode_extended) {} virtual bool process(const std::string& unknown_symbol, symbol_table_t& symbol_table, - std::string&) + std::string&) exprtk_override { static T v[1]; symbol_table.add_vector(unknown_symbol,v); @@ -37682,7 +42050,9 @@ namespace exprtk const symbol_table& sym_table = e.get_symbol_table(); if (!sym_table.valid()) + { return std::numeric_limits::quiet_NaN(); + } details::variable_node* var = sym_table.get_variable(variable_name); @@ -37695,8 +42065,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37786,8 +42156,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37813,8 +42183,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37840,8 +42210,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } /* @@ -38120,97 +42490,98 @@ namespace exprtk disable_has_side_effects(*this); } - virtual ~polynomial() {} + virtual ~polynomial() + {} #define poly_rtrn(NN) \ return (NN != N) ? std::numeric_limits::quiet_NaN() : - inline virtual T operator() (const T& x, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c1, const T& c0) exprtk_override { poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); } - inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, - const T& c0) + const T& c0) exprtk_override { poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, - const T& c1, const T& c0) + const T& c1, const T& c0) exprtk_override { poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, - const T& c2, const T& c1, const T& c0) + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, - const T& c3, const T& c2, const T& c1, const T& c0) + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, - const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, - const T& c0) + const T& c0) exprtk_override { poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, - const T& c1, const T& c0) + const T& c1, const T& c0) exprtk_override { poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, - const T& c2, const T& c1, const T& c0) + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, - const T& c3, const T& c2, const T& c1, const T& c0) + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } #undef poly_rtrn - inline virtual T operator() () + inline virtual T operator() () exprtk_override { return std::numeric_limits::quiet_NaN(); } - inline virtual T operator() (const T&) + inline virtual T operator() (const T&) exprtk_override { return std::numeric_limits::quiet_NaN(); } - inline virtual T operator() (const T&, const T&) + inline virtual T operator() (const T&, const T&) exprtk_override { return std::numeric_limits::quiet_NaN(); } @@ -38312,6 +42683,50 @@ namespace exprtk return (*this); } + inline function& vars(const std::string& v0, + const std::string& v1) + { + v_.push_back(v0); + v_.push_back(v1); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2, + const std::string& v3) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + v_.push_back(v3); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2, + const std::string& v3, + const std::string& v4) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + v_.push_back(v3); + v_.push_back(v4); + return (*this); + } + std::string name_; std::string expression_; std::deque v_; @@ -38321,12 +42736,14 @@ namespace exprtk struct base_func : public exprtk::ifunction { - typedef const T& type; - typedef exprtk::ifunction function_t; - typedef std::vector varref_t; - typedef std::vector var_t; + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; + typedef std::vector str_t; typedef std::pair lvarref_t; typedef std::vector lvr_vec_t; + typedef std::vector lstr_vec_t; using exprtk::ifunction::operator(); @@ -38338,10 +42755,11 @@ namespace exprtk v.resize(pc); } - virtual ~base_func() {} + virtual ~base_func() + {} - #define exprtk_assign(Index) \ - (*v[Index]) = v##Index; \ + #define exprtk_assign(Index) \ + (*v[Index]) = v##Index; \ inline void update(const T& v0) { @@ -38387,17 +42805,33 @@ namespace exprtk { expression = expr; - typedef typename expression_t::control_block::local_data_list_t ldl_t; + typedef typename expression_t::control_block ctrlblk_t; + typedef typename ctrlblk_t::local_data_list_t ldl_t; + typedef typename ctrlblk_t::data_type data_t; + typedef typename ldl_t::value_type ldl_value_type; const ldl_t ldl = expr.local_data_list(); - std::vector index_list; + std::vector > index_list; for (std::size_t i = 0; i < ldl.size(); ++i) { + exprtk_debug(("base_func::setup() - element[%02d] type: %s size: %d\n", + static_cast(i), + expression_t::control_block::to_str(ldl[i].type).c_str(), + static_cast(ldl[i].size))); + + switch (ldl[i].type) + { + case ctrlblk_t::e_unknown : continue; + case ctrlblk_t::e_expr : continue; + case ctrlblk_t::e_vecholder : continue; + default : break; + } + if (ldl[i].size) { - index_list.push_back(i); + index_list.push_back(std::make_pair(i,ldl[i].type)); } } @@ -38405,19 +42839,34 @@ namespace exprtk for (std::size_t i = 0; i < index_list.size(); ++i) { - const std::size_t index = index_list[i]; + const std::size_t index = index_list[i].first; + const ldl_value_type& local_var = ldl[index]; + + assert(local_var.pointer); if (i < (index_list.size() - v.size())) { - lv.push_back( - std::make_pair( - reinterpret_cast(ldl[index].pointer), - ldl[index].size)); + if (local_var.type == ctrlblk_t::e_string) + { + local_str_vars.push_back( + reinterpret_cast(local_var.pointer)); + } + else if ( + (local_var.type == ctrlblk_t::e_data ) || + (local_var.type == ctrlblk_t::e_vecdata) + ) + { + local_vars.push_back(std::make_pair( + reinterpret_cast(local_var.pointer), + local_var.size)); - local_var_stack_size += ldl[index].size; + local_var_stack_size += local_var.size; + } } else - v[input_param_count++] = reinterpret_cast(ldl[index].pointer); + { + v[input_param_count++] = reinterpret_cast(local_var.pointer); + } } clear_stack(); @@ -38433,14 +42882,21 @@ namespace exprtk { var_t var_stack(v.size(),T(0)); copy(v,var_stack); - param_stack.push_back(var_stack); + input_params_stack.push_back(var_stack); + } + + if (!local_vars.empty()) + { + var_t local_vec_frame(local_var_stack_size,T(0)); + copy(local_vars,local_vec_frame); + local_var_stack.push_back(local_vec_frame); } - if (!lv.empty()) + if (!local_str_vars.empty()) { - var_t local_var_stack(local_var_stack_size,T(0)); - copy(lv,local_var_stack); - local_stack.push_back(local_var_stack); + str_t local_str_frame(local_str_vars.size()); + copy(local_str_vars,local_str_frame); + local_str_stack.push_back(local_str_frame); } } } @@ -38451,14 +42907,20 @@ namespace exprtk { if (!v.empty()) { - copy(param_stack.back(),v); - param_stack.pop_back(); + copy(input_params_stack.back(), v); + input_params_stack.pop_back(); } - if (!lv.empty()) + if (!local_vars.empty()) { - copy(local_stack.back(),lv); - local_stack.pop_back(); + copy(local_var_stack.back(), local_vars); + local_var_stack.pop_back(); + } + + if (!local_str_vars.empty()) + { + copy(local_str_stack.back(), local_str_vars); + local_str_stack.pop_back(); } } } @@ -38471,6 +42933,14 @@ namespace exprtk } } + void copy(const lstr_vec_t& src_v, str_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + dest_v[i] = (*src_v[i]); + } + } + void copy(const var_t& src_v, varref_t& dest_v) { for (std::size_t i = 0; i < src_v.size(); ++i) @@ -38503,9 +42973,12 @@ namespace exprtk typename var_t::const_iterator itr = src_v.begin(); typedef typename std::iterator_traits::difference_type diff_t; - for (std::size_t i = 0; i < src_v.size(); ++i) + for (std::size_t i = 0; i < dest_v.size(); ++i) { - lvarref_t vr = dest_v[i]; + lvarref_t& vr = dest_v[i]; + + assert(vr.first != 0); + assert(vr.second > 0); if (1 == vr.second) (*vr.first) = *itr++; @@ -38517,6 +42990,16 @@ namespace exprtk } } + void copy(const str_t& src_str, lstr_vec_t& dest_str) + { + assert(src_str.size() == dest_str.size()); + + for (std::size_t i = 0; i < dest_str.size(); ++i) + { + *dest_str[i] = src_str[i]; + } + } + inline void clear_stack() { for (std::size_t i = 0; i < v.size(); ++i) @@ -38530,29 +43013,19 @@ namespace exprtk return e.value(); } - expression_t expression; - varref_t v; - lvr_vec_t lv; - std::size_t local_var_stack_size; - std::size_t stack_depth; - std::deque param_stack; - std::deque local_stack; + expression_t expression; + varref_t v; + lvr_vec_t local_vars; + lstr_vec_t local_str_vars; + std::size_t local_var_stack_size; + std::size_t stack_depth; + std::deque input_params_stack; + std::deque local_var_stack; + std::deque local_str_stack; }; typedef std::map funcparam_t; - struct func_0param : public base_func - { - using exprtk::ifunction::operator(); - - func_0param() : base_func(0) {} - - inline T operator() () - { - return this->value(base_func::expression); - } - }; - typedef const T& type; template @@ -38577,13 +43050,26 @@ namespace exprtk scoped_bft& operator=(const scoped_bft&) exprtk_delete; }; + struct func_0param : public base_func + { + using exprtk::ifunction::operator(); + + func_0param() : base_func(0) {} + + inline T operator() () exprtk_override + { + scoped_bft sb(*this); + return this->value(base_func::expression); + } + }; + struct func_1param : public base_func { using exprtk::ifunction::operator(); func_1param() : base_func(1) {} - inline T operator() (type v0) + inline T operator() (type v0) exprtk_override { scoped_bft sb(*this); base_func::update(v0); @@ -38597,7 +43083,7 @@ namespace exprtk func_2param() : base_func(2) {} - inline T operator() (type v0, type v1) + inline T operator() (type v0, type v1) exprtk_override { scoped_bft sb(*this); base_func::update(v0, v1); @@ -38611,7 +43097,7 @@ namespace exprtk func_3param() : base_func(3) {} - inline T operator() (type v0, type v1, type v2) + inline T operator() (type v0, type v1, type v2) exprtk_override { scoped_bft sb(*this); base_func::update(v0, v1, v2); @@ -38625,7 +43111,7 @@ namespace exprtk func_4param() : base_func(4) {} - inline T operator() (type v0, type v1, type v2, type v3) + inline T operator() (type v0, type v1, type v2, type v3) exprtk_override { scoped_bft sb(*this); base_func::update(v0, v1, v2, v3); @@ -38639,7 +43125,7 @@ namespace exprtk func_5param() : base_func(5) {} - inline T operator() (type v0, type v1, type v2, type v3, type v4) + inline T operator() (type v0, type v1, type v2, type v3, type v4) exprtk_override { scoped_bft sb(*this); base_func::update(v0, v1, v2, v3, v4); @@ -38653,7 +43139,7 @@ namespace exprtk func_6param() : base_func(6) {} - inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) + inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) exprtk_override { scoped_bft sb(*this); base_func::update(v0, v1, v2, v3, v4, v5); @@ -38680,14 +43166,14 @@ namespace exprtk return result; } - #define def_fp_retval(N) \ - struct func_##N##param_retval : public func_##N##param \ - { \ - inline T value(expression_t& e) \ - { \ - return return_value(e); \ - } \ - }; \ + #define def_fp_retval(N) \ + struct func_##N##param_retval exprtk_final : public func_##N##param \ + { \ + inline T value(expression_t& e) exprtk_override \ + { \ + return return_value(e); \ + } \ + }; \ def_fp_retval(0) def_fp_retval(1) @@ -38697,6 +43183,8 @@ namespace exprtk def_fp_retval(5) def_fp_retval(6) + #undef def_fp_retval + template class Sequence> inline bool add(const std::string& name, @@ -38739,16 +43227,20 @@ namespace exprtk public: function_compositor() - : parser_(settings_t::compile_all_opts + + : parser_(settings_t::default_compile_all_opts + settings_t::e_disable_zero_return) , fp_map_(7) + , load_variables_(false) + , load_vectors_(false) {} - function_compositor(const symbol_table_t& st) + explicit function_compositor(const symbol_table_t& st) : symbol_table_(st) - , parser_(settings_t::compile_all_opts + + , parser_(settings_t::default_compile_all_opts + settings_t::e_disable_zero_return) , fp_map_(7) + , load_variables_(false) + , load_vectors_(false) {} ~function_compositor() @@ -38771,6 +43263,46 @@ namespace exprtk auxiliary_symtab_list_.push_back(&symtab); } + void load_variables(const bool load = true) + { + load_variables_ = load; + } + + void load_vectors(const bool load = true) + { + load_vectors_ = load; + } + + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + parser_.register_loop_runtime_check(lrtchk); + } + + inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) + { + parser_.register_vector_access_runtime_check(vartchk); + } + + inline void register_compilation_timeout_check(compilation_check& compchk) + { + parser_.register_compilation_timeout_check(compchk); + } + + inline void clear_loop_runtime_check() + { + parser_.clear_loop_runtime_check(); + } + + inline void clear_vector_access_runtime_check() + { + parser_.clear_vector_access_runtime_check(); + } + + inline void clear_compilation_timeout_check() + { + parser_.clear_compilation_timeout_check(); + } + void clear() { symbol_table_.clear(); @@ -38789,6 +43321,10 @@ namespace exprtk fp_map_[i].clear(); } + + clear_loop_runtime_check (); + clear_vector_access_runtime_check(); + clear_compilation_timeout_check (); } inline bool add(const function& f, const bool override = false) @@ -38796,6 +43332,31 @@ namespace exprtk return add(f.name_, f.expression_, f.v_,override); } + inline std::string error() const + { + if (!error_list_.empty()) + { + return error_list_[0].diagnostic; + } + else + return std::string("No Error"); + } + + inline std::size_t error_count() const + { + return error_list_.size(); + } + + inline parser_error::type get_error(const std::size_t& index) const + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + + throw std::invalid_argument("compositor::get_error() - Invalid error index specified"); + } + private: template expr_map_; std::vector fp_map_; std::vector auxiliary_symtab_list_; + std::deque error_list_; + bool load_variables_; + bool load_vectors_; }; // class function_compositor } // namespace exprtk -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # ifndef NOMINMAX # define NOMINMAX # endif @@ -39001,9 +43591,11 @@ namespace exprtk { public: - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) timer() : in_use_(false) + , start_time_{ {0, 0} } + , stop_time_ { {0, 0} } { QueryPerformanceFrequency(&clock_frequency_); } @@ -39081,7 +43673,7 @@ namespace exprtk bool in_use_; - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) LARGE_INTEGER start_time_; LARGE_INTEGER stop_time_; LARGE_INTEGER clock_frequency_; @@ -39114,7 +43706,23 @@ namespace exprtk const T v, exprtk::details::numeric::details::real_type_tag) { - printf(fmt.c_str(),v); + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-nonliteral" + #elif defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + #elif defined(_MSC_VER) + #endif + + printf(fmt.c_str(), v); + + #if defined(__clang__) + #pragma clang diagnostic pop + #elif defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop + #elif defined(_MSC_VER) + #endif } template @@ -39174,19 +43782,19 @@ namespace exprtk } // namespace exprtk::rtl::io::details template - struct print : public exprtk::igeneric_function + struct print exprtk_final : public exprtk::igeneric_function { typedef typename igeneric_function::parameter_list_t parameter_list_t; using exprtk::igeneric_function::operator(); - print(const std::string& scalar_format = "%10.5f") + explicit print(const std::string& scalar_format = "%10.5f") : scalar_format_(scalar_format) { exprtk::enable_zero_parameters(*this); } - inline T operator() (parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) exprtk_override { details::print_impl::process(scalar_format_,parameters); return T(0); @@ -39196,19 +43804,19 @@ namespace exprtk }; template - struct println : public exprtk::igeneric_function + struct println exprtk_final : public exprtk::igeneric_function { typedef typename igeneric_function::parameter_list_t parameter_list_t; using exprtk::igeneric_function::operator(); - println(const std::string& scalar_format = "%10.5f") + explicit println(const std::string& scalar_format = "%10.5f") : scalar_format_(scalar_format) { exprtk::enable_zero_parameters(*this); } - inline T operator() (parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) exprtk_override { details::print_impl::process(scalar_format_,parameters); printf("\n"); @@ -39290,8 +43898,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -39306,8 +43914,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -39322,13 +43930,13 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } - else - return false; + + return false; } template @@ -39475,12 +44083,13 @@ namespace exprtk #ifdef _MSC_VER #pragma warning(pop) #endif + assert(sizeof(T) <= sizeof(void*)); } } // namespace exprtk::rtl::io::file::details template - class open : public exprtk::igeneric_function + class open exprtk_final : public exprtk::igeneric_function { public: @@ -39489,18 +44098,20 @@ namespace exprtk typedef typename igfun_t::generic_type generic_type; typedef typename generic_type::string_view string_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); open() : exprtk::igeneric_function("S|SS") { details::perform_check(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const std::string file_name = to_str(string_t(parameters[0])); if (file_name.empty()) + { return T(0); + } if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) { @@ -39532,7 +44143,7 @@ namespace exprtk }; template - struct close : public exprtk::ifunction + struct close exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); @@ -39540,7 +44151,7 @@ namespace exprtk : exprtk::ifunction(1) { details::perform_check(); } - inline T operator() (const T& v) + inline T operator() (const T& v) exprtk_override { details::file_descriptor* fd = details::make_handle(v); @@ -39554,7 +44165,7 @@ namespace exprtk }; template - class write : public exprtk::igeneric_function + class write exprtk_final : public exprtk::igeneric_function { public: @@ -39565,13 +44176,13 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); write() : igfun_t("TS|TST|TV|TVT") { details::perform_check(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); @@ -39611,7 +44222,7 @@ namespace exprtk }; template - class read : public exprtk::igeneric_function + class read exprtk_final : public exprtk::igeneric_function { public: @@ -39622,13 +44233,13 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); read() : igfun_t("TS|TST|TV|TVT") { details::perform_check(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); @@ -39668,7 +44279,7 @@ namespace exprtk }; template - class getline : public exprtk::igeneric_function + class getline exprtk_final : public exprtk::igeneric_function { public: @@ -39678,14 +44289,13 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::scalar_view scalar_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); getline() : igfun_t("T",igfun_t::e_rtrn_string) { details::perform_check(); } - inline T operator() (std::string& result, - parameter_list_t parameters) + inline T operator() (std::string& result, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); return T(fd->getline(result) ? 1 : 0); @@ -39693,7 +44303,7 @@ namespace exprtk }; template - struct eof : public exprtk::ifunction + struct eof exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); @@ -39701,10 +44311,9 @@ namespace exprtk : exprtk::ifunction(1) { details::perform_check(); } - inline T operator() (const T& v) + inline T operator() (const T& v) exprtk_override { details::file_descriptor* fd = details::make_handle(v); - return (fd->eof() ? T(1) : T(0)); } }; @@ -39814,44 +44423,61 @@ namespace exprtk } // namespace exprtk::rtl::details template - class all_true : public exprtk::igeneric_function + class all_true exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); all_true() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() == T(0)) + { + return T(0); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(0); + if (vec[i] == T(0)) + { + return T(0); + } } } @@ -39860,44 +44486,61 @@ namespace exprtk }; template - class all_false : public exprtk::igeneric_function + class all_false exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); all_false() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) + { + return T(0); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(0); + if (vec[i] != T(0)) + { + return T(0); + } } } @@ -39906,44 +44549,61 @@ namespace exprtk }; template - class any_true : public exprtk::igeneric_function + class any_true exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); any_true() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) + { + return T(1); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(1); + if (vec[i] != T(0)) + { + return T(1); + } } } @@ -39952,44 +44612,61 @@ namespace exprtk }; template - class any_false : public exprtk::igeneric_function + class any_false exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); any_false() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() == T(0)) + { + return T(1); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(1); + if (vec[i] == T(0)) + { + return T(1); + } } } @@ -39998,44 +44675,58 @@ namespace exprtk }; template - class count : public exprtk::igeneric_function + class count exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); count() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + std::size_t cnt = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) ++cnt; + } + } + else + { + const vector_t vec(parameters[0]); - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - std::size_t cnt = 0; + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) ++cnt; + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) ++cnt; + } } return T(cnt); @@ -40043,7 +44734,7 @@ namespace exprtk }; template - class copy : public exprtk::igeneric_function + class copy exprtk_final : public exprtk::igeneric_function { public: @@ -40053,7 +44744,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); copy() : exprtk::igeneric_function("VV|VTTVTT") @@ -40064,7 +44755,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); vector_t y(parameters[(0 == ps_index) ? 1 : 3]); @@ -40096,7 +44787,7 @@ namespace exprtk }; template - class rol : public exprtk::igeneric_function + class rol exprtk_final : public exprtk::igeneric_function { public: @@ -40106,7 +44797,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); rol() : exprtk::igeneric_function("VT|VTTT") @@ -40117,7 +44808,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40147,7 +44838,7 @@ namespace exprtk }; template - class ror : public exprtk::igeneric_function + class ror exprtk_final : public exprtk::igeneric_function { public: @@ -40157,7 +44848,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); ror() : exprtk::igeneric_function("VT|VTTT") @@ -40168,7 +44859,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40185,8 +44876,8 @@ namespace exprtk ) return T(0); - std::size_t dist = r1 - r0 + 1; - std::size_t shift = (dist - (n % dist)) % dist; + const std::size_t dist = r1 - r0 + 1; + const std::size_t shift = (dist - (n % dist)) % dist; std::rotate( vec.begin() + r0, @@ -40198,7 +44889,7 @@ namespace exprtk }; template - class shift_left : public exprtk::igeneric_function + class reverse exprtk_final : public exprtk::igeneric_function { public: @@ -40208,7 +44899,48 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + reverse() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return T(0); + + std::reverse(vec.begin() + r0, vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class shift_left exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); shift_left() : exprtk::igeneric_function("VT|VTTT") @@ -40219,7 +44951,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40246,7 +44978,7 @@ namespace exprtk vec.begin() + r0 + n, vec.begin() + r1 + 1); - for (std::size_t i = r1 - n + 1; i <= r1; ++i) + for (std::size_t i = r1 - n + 1ULL; i <= r1; ++i) { vec[i] = T(0); } @@ -40256,7 +44988,7 @@ namespace exprtk }; template - class shift_right : public exprtk::igeneric_function + class shift_right exprtk_final : public exprtk::igeneric_function { public: @@ -40266,7 +44998,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); shift_right() : exprtk::igeneric_function("VT|VTTT") @@ -40277,7 +45009,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40316,7 +45048,7 @@ namespace exprtk }; template - class sort : public exprtk::igeneric_function + class sort exprtk_final : public exprtk::igeneric_function { public: @@ -40326,7 +45058,7 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); sort() : exprtk::igeneric_function("V|VTT|VS|VSTT") @@ -40339,7 +45071,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40379,7 +45111,7 @@ namespace exprtk }; template - class nthelement : public exprtk::igeneric_function + class nthelement exprtk_final : public exprtk::igeneric_function { public: @@ -40389,7 +45121,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); nthelement() : exprtk::igeneric_function("VT|VTTT") @@ -40400,7 +45132,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -40412,7 +45144,9 @@ namespace exprtk return T(0); if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + { return std::numeric_limits::quiet_NaN(); + } std::nth_element( vec.begin() + r0, @@ -40424,7 +45158,7 @@ namespace exprtk }; template - class iota : public exprtk::igeneric_function + class assign exprtk_final : public exprtk::igeneric_function { public: @@ -40434,41 +45168,101 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + assign() + : exprtk::igeneric_function("VT|VTTT|VTTTT") + /* + Overloads: + 0. VT - vector, V + 1. VTTT - vector, V, r0, r1 + 2. VTTTT - vector, V, r0, r1, SS + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T assign_value = scalar_t(parameters[1]); + + const std::size_t step_size = (2 != ps_index) ? 1 : + static_cast(scalar_t(parameters.back())()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + ((ps_index == 1) || (ps_index == 2)) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; i += step_size) + { + vec[i] = assign_value; + } + + return T(1); + } + }; + + template + class iota exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); iota() - : exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") + : exprtk::igeneric_function("VTT|VT|VTTTT|VTTT") /* Overloads: - 0. VT - vector, increment - 1. VTT - vector, increment, base - 2. VTTTT - vector, increment, r0, r1 - 3. VTTTT - vector, increment, base, r0, r1 + 0. VTT - vector, SV, SS + 1. VT - vector, SV, SS (+1) + 2. VTTT - vector, r0, r1, SV, SS + 3. VTT - vector, r0, r1, SV, SS (+1) + + Where: + 1. SV - Start value + 2. SS - Step size */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); - T increment = scalar_t(parameters[1])(); - T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + const T start_value = (ps_index <= 1) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T step_size = ((0 == ps_index) || (2 == ps_index)) ? + scalar_t(parameters.back())() : + T(1) ; std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((2 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) - return std::numeric_limits::quiet_NaN(); - else if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 0)) - return std::numeric_limits::quiet_NaN(); - else + if ( + ((ps_index == 2) || (ps_index == 3)) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) { - long long j = 0; + return T(0); + } - for (std::size_t i = r0; i <= r1; ++i, ++j) - { - vec[i] = base + (increment * j); - } + for (std::size_t i = r0; i <= r1; ++i) + { + vec[i] = start_value + ((i - r0) * step_size); } return T(1); @@ -40476,40 +45270,50 @@ namespace exprtk }; template - class sumk : public exprtk::igeneric_function + class sumk exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); sumk() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("V|VTT|VTTT") /* Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VTTT - vector, r0, r1, stride */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t vec(parameters[0]); + const std::size_t stride = (2 != ps_index) ? 1 : + static_cast(scalar_t(parameters[3])()); + std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + if ( + ((1 == ps_index) || (2 == ps_index)) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { return std::numeric_limits::quiet_NaN(); + } T result = T(0); T error = T(0); - for (std::size_t i = r0; i <= r1; ++i) + for (std::size_t i = r0; i <= r1; i += stride) { details::kahan_sum(result, error, vec[i]); } @@ -40519,7 +45323,7 @@ namespace exprtk }; template - class axpy : public exprtk::igeneric_function + class axpy exprtk_final : public exprtk::igeneric_function { public: @@ -40529,7 +45333,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpy() : exprtk::igeneric_function("TVV|TVVTT") @@ -40541,7 +45345,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t y(parameters[2]); @@ -40566,7 +45370,7 @@ namespace exprtk }; template - class axpby : public exprtk::igeneric_function + class axpby exprtk_final : public exprtk::igeneric_function { public: @@ -40576,7 +45380,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpby() : exprtk::igeneric_function("TVTV|TVTVTT") @@ -40588,7 +45392,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t y(parameters[3]); @@ -40614,7 +45418,7 @@ namespace exprtk }; template - class axpyz : public exprtk::igeneric_function + class axpyz exprtk_final : public exprtk::igeneric_function { public: @@ -40624,7 +45428,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpyz() : exprtk::igeneric_function("TVVV|TVVVTT") @@ -40636,7 +45440,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); const vector_t y(parameters[2]); @@ -40645,7 +45449,7 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); @@ -40664,7 +45468,7 @@ namespace exprtk }; template - class axpbyz : public exprtk::igeneric_function + class axpbyz exprtk_final : public exprtk::igeneric_function { public: @@ -40674,7 +45478,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpbyz() : exprtk::igeneric_function("TVTVV|TVTVVTT") @@ -40686,7 +45490,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); const vector_t y(parameters[3]); @@ -40695,7 +45499,7 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 5, 6, 1)) return std::numeric_limits::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); @@ -40715,7 +45519,7 @@ namespace exprtk }; template - class axpbz : public exprtk::igeneric_function + class axpbsy exprtk_final : public exprtk::igeneric_function { public: @@ -40725,7 +45529,110 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + axpbsy() + : exprtk::igeneric_function("TVTTV|TVTTVTT") + /* + y <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[1]); + vector_t y(parameters[4]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 5, 6, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast(scalar_t(parameters[3])()); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + (b * y[i + s]); + } + + return T(1); + } + }; + + template + class axpbsyz exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + axpbsyz() + : exprtk::igeneric_function("TVTTVV|TVTTVVTT") + /* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[1]); + const vector_t y(parameters[4]); + vector_t z(parameters[5]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 6, 7, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast(scalar_t(parameters[3])()); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + (b * y[i + s]); + } + + return T(1); + } + }; + + template + class axpbz exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); axpbz() : exprtk::igeneric_function("TVTV|TVTVTT") @@ -40737,7 +45644,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t z(parameters[3]); @@ -40763,7 +45670,7 @@ namespace exprtk }; template - class dot : public exprtk::igeneric_function + class diff exprtk_final : public exprtk::igeneric_function { public: @@ -40773,7 +45680,55 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + diff() + : exprtk::igeneric_function("VV|VVT") + /* + x_(i - stride) - x_i + Overloads: + 0. VV - x(vector), y(vector) + 1. VVT - x(vector), y(vector), stride + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[0]); + vector_t y(parameters[1]); + + const std::size_t r0 = 0; + const std::size_t r1 = std::min(x.size(),y.size()) - 1; + + const std::size_t stride = (1 != ps_index) ? 1 : + std::min(r1,static_cast(scalar_t(parameters[2])())); + + for (std::size_t i = 0; i < stride; ++i) + { + y[i] = std::numeric_limits::quiet_NaN(); + } + + for (std::size_t i = (r0 + stride); i <= r1; ++i) + { + y[i] = x[i] - x[i - stride]; + } + + return T(1); + } + }; + + template + class dot exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); dot() : exprtk::igeneric_function("VV|VVTT") @@ -40784,7 +45739,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); const vector_t y(parameters[1]); @@ -40809,7 +45764,7 @@ namespace exprtk }; template - class dotk : public exprtk::igeneric_function + class dotk exprtk_final : public exprtk::igeneric_function { public: @@ -40819,7 +45774,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); dotk() : exprtk::igeneric_function("VV|VVTT") @@ -40830,7 +45785,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); const vector_t y(parameters[1]); @@ -40855,30 +45810,155 @@ namespace exprtk } }; + template + class threshold_below exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + threshold_below() + : exprtk::igeneric_function("VTT|VTTTT") + /* + Overloads: + 0. VTT - vector, TV, SV + 1. VTTTT - vector, r0, r1, TV, SV + + Where: + TV - Threshold value + SV - Snap-to value + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T threshold_value = (0 == ps_index) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T snap_value = scalar_t(parameters.back()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] < threshold_value) + { + vec[i] = snap_value; + } + } + + return T(1); + } + }; + + template + class threshold_above exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + threshold_above() + : exprtk::igeneric_function("VTT|VTTTT") + /* + Overloads: + 0. VTT - vector, TV, SV + 1. VTTTT - vector, r0, r1, TV, SV + + Where: + TV - Threshold value + SV - Snap-to value + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T threshold_value = (0 == ps_index) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T snap_value = scalar_t(parameters.back()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] > threshold_value) + { + vec[i] = snap_value; + } + } + + return T(1); + } + }; + template struct package { - all_true at; - all_false af; - any_true nt; - any_false nf; - count c; - copy cp; - rol rl; - ror rr; - shift_left sl; - shift_right sr; - sort st; - nthelement ne; - iota ia; - sumk sk; - axpy b1_axpy; - axpby b1_axpby; - axpyz b1_axpyz; - axpbyz b1_axpbyz; - axpbz b1_axpbz; - dot dt; - dotk dtk; + all_true at; + all_false af; + any_true nt; + any_false nf; + count c; + copy cp; + rol rl; + ror rr; + reverse rev; + shift_left sl; + shift_right sr; + sort st; + nthelement ne; + assign an; + iota ia; + sumk sk; + axpy b1_axpy; + axpby b1_axpby; + axpyz b1_axpyz; + axpbyz b1_axpbyz; + axpbsy b1_axpbsy; + axpbsyz b1_axpbsyz; + axpbz b1_axpbz; + diff df; + dot dt; + dotk dtk; + threshold_above ta; + threshold_below tb; bool register_package(exprtk::symbol_table& symtab) { @@ -40891,29 +45971,36 @@ namespace exprtk return false; \ } \ - exprtk_register_function("all_true" , at ) - exprtk_register_function("all_false" , af ) - exprtk_register_function("any_true" , nt ) - exprtk_register_function("any_false" , nf ) - exprtk_register_function("count" , c ) - exprtk_register_function("copy" , cp ) - exprtk_register_function("rotate_left" , rl ) - exprtk_register_function("rol" , rl ) - exprtk_register_function("rotate_right" , rr ) - exprtk_register_function("ror" , rr ) - exprtk_register_function("shftl" , sl ) - exprtk_register_function("shftr" , sr ) - exprtk_register_function("sort" , st ) - exprtk_register_function("nth_element" , ne ) - exprtk_register_function("iota" , ia ) - exprtk_register_function("sumk" , sk ) - exprtk_register_function("axpy" , b1_axpy ) - exprtk_register_function("axpby" , b1_axpby ) - exprtk_register_function("axpyz" , b1_axpyz ) - exprtk_register_function("axpbyz" , b1_axpbyz) - exprtk_register_function("axpbz" , b1_axpbz ) - exprtk_register_function("dot" , dt ) - exprtk_register_function("dotk" , dtk ) + exprtk_register_function("all_true" , at ) + exprtk_register_function("all_false" , af ) + exprtk_register_function("any_true" , nt ) + exprtk_register_function("any_false" , nf ) + exprtk_register_function("count" , c ) + exprtk_register_function("copy" , cp ) + exprtk_register_function("rotate_left" , rl ) + exprtk_register_function("rol" , rl ) + exprtk_register_function("rotate_right" , rr ) + exprtk_register_function("ror" , rr ) + exprtk_register_function("reverse" , rev ) + exprtk_register_function("shftl" , sl ) + exprtk_register_function("shftr" , sr ) + exprtk_register_function("sort" , st ) + exprtk_register_function("nth_element" , ne ) + exprtk_register_function("assign" , an ) + exprtk_register_function("iota" , ia ) + exprtk_register_function("sumk" , sk ) + exprtk_register_function("axpy" , b1_axpy ) + exprtk_register_function("axpby" , b1_axpby ) + exprtk_register_function("axpyz" , b1_axpyz ) + exprtk_register_function("axpbyz" , b1_axpbyz ) + exprtk_register_function("axpbsy" , b1_axpbsy ) + exprtk_register_function("axpbsyz" , b1_axpbsyz) + exprtk_register_function("axpbz" , b1_axpbz ) + exprtk_register_function("diff" , df ) + exprtk_register_function("dot" , dt ) + exprtk_register_function("dotk" , dtk ) + exprtk_register_function("threshold_above" , ta ) + exprtk_register_function("threshold_below" , tb ) #undef exprtk_register_function return true; @@ -40932,11 +46019,11 @@ namespace exprtk using ::exprtk::details::char_cptr; static char_cptr library = "Mathematical Expression Toolkit"; - static char_cptr version = "2.71828182845904523536028747135266" - "2497757247093699959574966967627724" - "0766303535475945713821785251664274" - "2746639193200305992181741359662904"; - static char_cptr date = "20230101"; + static char_cptr version = "2.718281828459045235360287471352662497757" + "24709369995957496696762772407663035354759" + "45713821785251664274274663919320030599218" + "17413596629043572900334295260595630738132"; + static char_cptr date = "20240101"; static char_cptr min_cpp = "199711L"; static inline std::string data() @@ -40958,12 +46045,8 @@ namespace exprtk #undef exprtk_error_location #endif - #ifdef exprtk_disable_fallthrough_begin - #undef exprtk_disable_fallthrough_begin - #endif - - #ifdef exprtk_disable_fallthrough_end - #undef exprtk_disable_fallthrough_end + #ifdef exprtk_fallthrough + #undef exprtk_fallthrough #endif #ifdef exprtk_override From d96e711a34ce621b5a37e0506e8b315f0a5bf10a Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 19 Jan 2024 16:03:43 +0800 Subject: [PATCH 089/144] change ms and lost rate --- web/js/serverstatus.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index ce3a6923..43c12375 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -82,7 +82,6 @@ function uptime() { "
加载中
" + "
加载中
" + "
加载中
" + - "
加载中
" + "
加载中
" + "
" ); @@ -255,13 +254,14 @@ function uptime() { // tcp, udp, process, thread count ExpandRow[0].children["expand_tupd"].innerHTML = "TCP/UDP/进/线: " + result.servers[i].tcp_count + " / " + result.servers[i].udp_count + " / " + result.servers[i].process_count+ " / " + result.servers[i].thread_count; - ExpandRow[0].children["expand_ping"].innerHTML = "联通/电信/移动: " + result.servers[i].time_10010 + "ms / " + result.servers[i].time_189 + "ms / " + result.servers[i].time_10086 + "ms" // ping var PING_10010 = result.servers[i].ping_10010.toFixed(0); var PING_189 = result.servers[i].ping_189.toFixed(0); var PING_10086 = result.servers[i].ping_10086.toFixed(0); - ExpandRow[0].children["expand_lost"].innerHTML = "丢包:联通/电信/移动: " + PING_10010 + "% / " + PING_189 + "% / " + PING_10086 + "%" + + // ping ms + lost rate + ExpandRow[0].children["expand_ping"].innerHTML = "CU/CT/CM: " + result.servers[i].time_10010 + "ms ("+result.servers[i].ping_10010.toFixed(0)+"%) / " + result.servers[i].time_189 + "ms ("+result.servers[i].ping_189.toFixed(0)+"%) / " + result.servers[i].time_10086 + "ms ("+result.servers[i].ping_10086.toFixed(0)+"%)" if (PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20) TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger"; From 71cadcfebe05d97fb609b2b380ff82213f01faa0 Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 21 Jan 2024 21:09:37 +0800 Subject: [PATCH 090/144] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E9=87=8D=E8=A6=81=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/client-linux.py | 118 +++++++++++++++++++++++++++++++++++++-- clients/client-psutil.py | 118 +++++++++++++++++++++++++++++++++++++-- server/config.json | 40 +++++++++---- server/src/main.cpp | 34 +++++++++++ server/src/main.h | 11 +++- web/css/dark.css | 66 +++++++++------------- web/css/light.css | 66 +++++++++------------- web/index.html | 73 ++++++++++++++++-------- web/js/serverstatus.js | 42 +++++++++++--- 9 files changed, 434 insertions(+), 134 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 00e59d5c..05744530 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -20,6 +20,7 @@ INTERVAL = 1 import socket +import ssl import time import timeit import re @@ -29,10 +30,10 @@ import errno import subprocess import threading -try: - from queue import Queue # python3 -except ImportError: - from Queue import Queue # python2 +if sys.version_info.major == 3: + from queue import Queue +elif sys.version_info.major == 2: + from Queue import Queue def get_uptime(): with open('/proc/uptime', 'r') as f: @@ -150,6 +151,7 @@ def get_network(ip_version): 'read': 0, 'write': 0 } +monitorServer = {} def _ping_thread(host, mark, port): lostPacket = 0 @@ -314,6 +316,97 @@ def get_realtime_data(): ti.daemon = True ti.start() + +def _monitor_thread(name, host, interval, type): + lostPacket = 0 + packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN) + while True: + if name not in monitorServer.keys(): + monitorServer[name] = { + "type": type, + "dns_time": 0, + "connect_time": 0, + "download_time": 0, + "online_rate": 1 + } + if packet_queue.full(): + if packet_queue.get() == 0: + lostPacket -= 1 + try: + if type == "http": + address = host.replace("http://", "") + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, 80), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + response = b"" + while True: + data = k.recv(4096) + if not data: + break + response += data + http_code = response.decode('utf-8').split('\r\n')[0].split()[1] + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + k.close() + if http_code not in ['200', '204', '301', '302', '401']: + raise Exception("http code not in 200, 204, 301, 302, 401") + elif type == "https": + context = ssl._create_unverified_context() + address = host.replace("https://", "") + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, 443), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + kk = context.wrap_socket(k, server_hostname=address) + kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + response = b"" + while True: + data = kk.recv(4096) + if not data: + break + response += data + http_code = response.decode('utf-8').split('\r\n')[0].split()[1] + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + kk.close() + k.close() + if http_code not in ['200', '204', '301', '302', '401']: + raise Exception("http code not in 200, 204, 301, 302, 401") + elif type == "tcp": + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, int(host.split(":")[1])), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k.send(b"GET / HTTP/1.2\r\n\r\n") + k.recv(1024) + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + k.close() + packet_queue.put(1) + except Exception as e: + lostPacket += 1 + packet_queue.put(0) + if packet_queue.qsize() > 5: + monitorServer[name]["online_rate"] = 1 - float(lostPacket) / packet_queue.qsize() + time.sleep(interval) + def byte_str(object): ''' bytes to str, str to bytes @@ -360,6 +453,20 @@ def byte_str(object): if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) + for i in data.split('\n'): + if "monitor" in i and "type" in i and "{" in i and "}" in i: + jdata = json.loads(i[i.find("{"):i.find("}")+1]) + t = threading.Thread( + target=_monitor_thread, + kwargs={ + 'name': jdata.get("name"), + 'host': jdata.get("host"), + 'interval': jdata.get("interval"), + 'type': jdata.get("type") + } + ) + t.daemon = True + t.start() timer = 0 check_ip = 0 @@ -378,7 +485,6 @@ def byte_str(object): Load_1, Load_5, Load_15 = os.getloadavg() MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory() HDDTotal, HDDUsed = get_hdd() - array = {} if not timer: array['online' + str(check_ip)] = get_network(check_ip) @@ -412,7 +518,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise diff --git a/clients/client-psutil.py b/clients/client-psutil.py index ceac788a..c2b39281 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -21,6 +21,7 @@ INTERVAL = 1 import socket +import ssl import time import timeit import os @@ -29,10 +30,10 @@ import errno import psutil import threading -try: - from queue import Queue # python3 -except ImportError: - from Queue import Queue # python2 +if sys.version_info.major == 3: + from queue import Queue +elif sys.version_info.major == 2: + from Queue import Queue def get_uptime(): return int(time.time() - psutil.boot_time()) @@ -148,6 +149,7 @@ def get_network(ip_version): 'read': 0, 'write': 0 } +monitorServer = {} def _ping_thread(host, mark, port): lostPacket = 0 @@ -303,6 +305,97 @@ def get_realtime_data(): ti.daemon = True ti.start() +def _monitor_thread(name, host, interval, type): + lostPacket = 0 + packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN) + while True: + if name not in monitorServer.keys(): + monitorServer[name] = { + "type": type, + "dns_time": 0, + "connect_time": 0, + "download_time": 0, + "online_rate": 1 + } + if packet_queue.full(): + if packet_queue.get() == 0: + lostPacket -= 1 + try: + if type == "http": + address = host.replace("http://", "") + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, 80), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + response = b"" + while True: + data = k.recv(4096) + if not data: + break + response += data + http_code = response.decode('utf-8').split('\r\n')[0].split()[1] + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + k.close() + if http_code not in ['200', '204', '301', '302', '401']: + raise Exception("http code not in 200, 204, 301, 302, 401") + elif type == "https": + context = ssl._create_unverified_context() + address = host.replace("https://", "") + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, 443), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + kk = context.wrap_socket(k, server_hostname=address) + kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + response = b"" + while True: + data = kk.recv(4096) + if not data: + break + response += data + http_code = response.decode('utf-8').split('\r\n')[0].split()[1] + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + kk.close() + k.close() + if http_code not in ['200', '204', '301', '302', '401']: + raise Exception("http code not in 200, 204, 301, 302, 401") + elif type == "tcp": + m = timeit.default_timer() + if PROBE_PROTOCOL_PREFER == 'ipv4': + IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET)[0][4][0] + else: + IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET6)[0][4][0] + monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k = socket.create_connection((IP, int(host.split(":")[1])), timeout=6) + monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) + m = timeit.default_timer() + k.send(b"GET / HTTP/1.2\r\n\r\n") + k.recv(1024) + monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000) + k.close() + packet_queue.put(1) + except Exception as e: + lostPacket += 1 + packet_queue.put(0) + if packet_queue.qsize() > 5: + monitorServer[name]["online_rate"] = 1 - float(lostPacket) / packet_queue.qsize() + time.sleep(interval) + + def byte_str(object): ''' bytes to str, str to bytes @@ -349,6 +442,20 @@ def byte_str(object): if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) + for i in data.split('\n'): + if "monitor" in i and "type" in i and "{" in i and "}" in i: + jdata = json.loads(i[i.find("{"):i.find("}")+1]) + t = threading.Thread( + target=_monitor_thread, + kwargs={ + 'name': jdata.get("name"), + 'host': jdata.get("host"), + 'interval': jdata.get("interval"), + 'type': jdata.get("type") + } + ) + t.daemon = True + t.start() timer = 0 check_ip = 0 @@ -368,7 +475,6 @@ def byte_str(object): MemoryTotal, MemoryUsed = get_memory() SwapTotal, SwapUsed = get_swap() HDDTotal, HDDUsed = get_hdd() - array = {} if not timer: array['online' + str(check_ip)] = get_network(check_ip) @@ -402,7 +508,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise diff --git a/server/config.json b/server/config.json index c60018ff..29a4df47 100644 --- a/server/config.json +++ b/server/config.json @@ -38,6 +38,26 @@ "monthstart": 1 } ], + "monitors": [ + { + "name": "百度一下", + "host": "https://www.baidu.com", + "interval": 60, + "type": "https" + }, + { + "name": "主机交流", + "host": "https://www.hostloc.com", + "interval": 60, + "type": "https" + }, + { + "name": "DNS服务", + "host": "114.114.114.114:53", + "interval": 60, + "type": "tcp" + } + ], "watchdog": [ { "name": "cpu high warning,exclude username s01", @@ -58,17 +78,17 @@ "callback": "https://yourSMSurl" }, { - "name": "ddcc attack,limit type Oracle", - "rule": "tcp_count>600&type='Oracle'", - "interval": 300, - "callback": "https://yourSMSurl" - }, + "name": "ddcc attack,limit type Oracle", + "rule": "tcp_count>600&type='Oracle'", + "interval": 300, + "callback": "https://yourSMSurl" + }, { - "name": "month traffic warning", - "rule": "(network_out-last_network_out)/1024/1024/1024>999", - "interval": 3600, - "callback": "https://yourSMSurl" - }, + "name": "month traffic warning", + "rule": "(network_out-last_network_out)/1024/1024/1024>999", + "interval": 3600, + "callback": "https://yourSMSurl" + }, { "name": "you can parse an expression combining any known field", "rule": "load_5>3", diff --git a/server/src/main.cpp b/server/src/main.cpp index d24d6057..2dc5c434 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -92,6 +92,18 @@ void CMain::OnNewClient(int ClientNetID, int ClientID) Client(ClientID)->m_Stats.m_Online4 = true; else if(Client(ClientID)->m_ClientNetType == NETTYPE_IPV6) Client(ClientID)->m_Stats.m_Online6 = true; + + // Send monitor to client + // support by cpp.la + int ID = 0; + char monitorBuffer[2048]; + while (strcmp(Monitors(ID)->m_aName, "NULL")) + { + memset(monitorBuffer, 0, sizeof(monitorBuffer)); + sprintf(monitorBuffer, "{\"name\":\"%s\",\"host\":\"%s\",\"interval\":%d,\"type\":\"%s\",\"monitor\":%d}", Monitors(ID)->m_aName, Monitors(ID)->m_aHost, Monitors(ID)->m_aInterval, Monitors(ID)->m_aType, ID); + m_Server.Network()->Send(ClientNetID, monitorBuffer); + ID++; + } } void CMain::OnDelClient(int ClientNetID) @@ -572,6 +584,28 @@ int CMain::ReadConfig() } else str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); + // monitor + // support by: https://cpp.la + ID = 0; + const json_value &mStart = (*pJsonData)["monitors"]; + if(mStart.type == json_array) + { + for(unsigned i = 0; i < mStart.u.array.length; i++) + { + if(ID < 0 || ID >= NET_MAX_CLIENTS) + continue; + + str_copy(Monitors(ID)->m_aName, mStart[i]["name"].u.string.ptr, sizeof(Monitors(ID)->m_aName)); + str_copy(Monitors(ID)->m_aHost, mStart[i]["host"].u.string.ptr, sizeof(Monitors(ID)->m_aHost)); + Monitors(ID)->m_aInterval = mStart[i]["interval"].u.integer; + str_copy(Monitors(ID)->m_aType, mStart[i]["type"].u.string.ptr, sizeof(Monitors(ID)->m_aType)); + + ID++; + } + str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName)); + } else + str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName)); + // if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT // support by: https://cpp.la IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ); diff --git a/server/src/main.h b/server/src/main.h index eb3fb3ef..848d2468 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -77,7 +77,7 @@ class CMain int64_t m_IORead; int64_t m_IOWrite; double m_CPU; - char m_aCustom[512]; + char m_aCustom[1024]; // Options bool m_Pong; } m_Stats; @@ -90,6 +90,13 @@ class CMain char m_aCallback[1024]; } m_aCWatchDogs[NET_MAX_CLIENTS]; + struct CMonitors{ + char m_aName[128]; + char m_aHost[128]; + int m_aInterval; + char m_aType[128]; + } m_aCMonitors[NET_MAX_CLIENTS]; + struct CJSONUpdateThreadData { CClient *pClients; @@ -108,6 +115,8 @@ class CMain int Run(); CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } + CMonitors *Monitors(int ruleID) { return &m_aCMonitors[ruleID]; } + void WatchdogMessage(int ClientNetID, double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, double time_10010, double time_189, double time_10086, double tcp_count, double udp_count, double process_count, double thread_count, diff --git a/web/css/dark.css b/web/css/dark.css index 5bfb9491..eea98f36 100644 --- a/web/css/dark.css +++ b/web/css/dark.css @@ -23,48 +23,32 @@ tr.odd.expandRow > :hover { background: #212e36 !important; } #ping { max-width: 110px; } @media only screen and (max-width: 1200px) { - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + #server { + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } } @media only screen and (max-width: 720px) { - body { font-size: 10px; } - .content { padding: 0; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + #server { + body { font-size: 10px; } + .content { padding: 0; } + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } } @media only screen and (max-width: 620px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} -@media only screen and (max-width: 533px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} -@media only screen and (max-width: 450px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #name, tr td:nth-child(3) { min-width: 55px; max-width: 85px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #cpu, #ram, #hdd { min-width: 25px; max-width: 50px; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} + #server { + body { font-size: 10px; } + .content { padding: 0; } + #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } +} \ No newline at end of file diff --git a/web/css/light.css b/web/css/light.css index e881dcb5..37e7f775 100644 --- a/web/css/light.css +++ b/web/css/light.css @@ -20,48 +20,32 @@ tr.odd.expandRow > :hover { background: #FFF !important; } #ping { max-width: 110px; } @media only screen and (max-width: 1200px) { - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + #server { + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } } @media only screen and (max-width: 720px) { - body { font-size: 10px; } - .content { padding: 0; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + #server { + body { font-size: 10px; } + .content { padding: 0; } + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } } @media only screen and (max-width: 620px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} -@media only screen and (max-width: 533px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} -@media only screen and (max-width: 450px) { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #name, tr td:nth-child(3) { min-width: 55px; max-width: 85px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #cpu, #ram, #hdd { min-width: 25px; max-width: 50px; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } -} + #server { + body { font-size: 10px; } + .content { padding: 0; } + #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } + #type, tr td:nth-child(4) { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } + } +} \ No newline at end of file diff --git a/web/index.html b/web/index.html index ed68d630..5fa61757 100644 --- a/web/index.html +++ b/web/index.html @@ -47,6 +47,12 @@

- - - - - - - - - - - - - - - - - - - - - -
🔗协议📊月流量↓|↑📌节点🗂️虚拟化🌍位置⏱️在线负载🚦网络↓|↑📋总流量↓|↑🎯核芯⚡️内存💾硬盘🌐CU|CT|CM
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + +
🔗协议📊月流量↓|↑📌节点🗂️虚拟化🌍位置⏱️在线负载🚦网络↓|↑📋总流量↓|↑🎯核芯⚡️内存💾硬盘🌐CU|CT|CM
+
+
+ + + + + + + + + + + + + +
🔗协议📌监测节点🌍监测位置📋监测内容
+
+
+
Updating...
diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index 43c12375..529456c0 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -57,6 +57,7 @@ function uptime() { for (var i = 0, rlen=result.servers.length; i < rlen; i++) { var TableRow = $("#servers tr#r" + i); + var MableRow = $("#monitors tr#r" + i); var ExpandRow = $("#servers #rt" + i); var hack; // fuck CSS for making me do this if(i%2) hack="odd"; else hack="even"; @@ -82,16 +83,28 @@ function uptime() { "
加载中
" + "
加载中
" + "
加载中
" + - "
加载中
" + "" ); TableRow = $("#servers tr#r" + i); ExpandRow = $("#servers #rt" + i); server_status[i] = true; } + if (!MableRow.length) { + $("#monitors").append( + "" + + "
加载中
" + + "加载中" + + "加载中" + + "加载中" + + "" + ); + MableRow = $("#monitors tr#r" + i); + } TableRow = TableRow[0]; + MableRow = MableRow[0]; if(error) { TableRow.setAttribute("data-target", "#rt" + i); + MableRow.setAttribute("data-target", "#rt" + i); server_status[i] = true; } @@ -99,25 +112,35 @@ function uptime() { if (result.servers[i].online4 && !result.servers[i].online6) { TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["online_status"].children[0].children[0].innerHTML = "IPv4"; + MableRow.children["monitor_status"].children[0].children[0].className = "progress-bar progress-bar-success"; + MableRow.children["monitor_status"].children[0].children[0].innerHTML = "IPv4"; } else if (result.servers[i].online4 && result.servers[i].online6) { TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["online_status"].children[0].children[0].innerHTML = "双栈"; + MableRow.children["monitor_status"].children[0].children[0].className = "progress-bar progress-bar-success"; + MableRow.children["monitor_status"].children[0].children[0].innerHTML = "双栈"; } else if (!result.servers[i].online4 && result.servers[i].online6) { TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["online_status"].children[0].children[0].innerHTML = "IPv6"; + MableRow.children["monitor_status"].children[0].children[0].className = "progress-bar progress-bar-success"; + MableRow.children["monitor_status"].children[0].children[0].innerHTML = "IPv6"; } else { TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-danger"; TableRow.children["online_status"].children[0].children[0].innerHTML = "关闭"; + MableRow.children["monitor_status"].children[0].children[0].className = "progress-bar progress-bar-danger"; + MableRow.children["monitor_status"].children[0].children[0].innerHTML = "关闭"; } // Name TableRow.children["name"].innerHTML = result.servers[i].name; + MableRow.children["monitor_node"].innerHTML = result.servers[i].name; // Type TableRow.children["type"].innerHTML = result.servers[i].type; // Location TableRow.children["location"].innerHTML = result.servers[i].location; + MableRow.children["monitor_location"].innerHTML = result.servers[i].location; if (!result.servers[i].online4 && !result.servers[i].online6) { if (server_status[i]) { TableRow.children["uptime"].innerHTML = "–"; @@ -138,15 +161,18 @@ function uptime() { TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger"; TableRow.children["ping"].children[0].children[0].style.width = "100%"; TableRow.children["ping"].children[0].children[0].innerHTML = "关闭"; + MableRow.children["monitor_text"].innerHTML = "-"; if(ExpandRow.hasClass("in")) { ExpandRow.collapse("hide"); } TableRow.setAttribute("data-target", ""); + MableRow.setAttribute("data-target", ""); server_status[i] = false; } } else { if (!server_status[i]) { TableRow.setAttribute("data-target", "#rt" + i); + MableRow.setAttribute("data-target", "#rt" + i); server_status[i] = true; } @@ -271,12 +297,8 @@ function uptime() { TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-success"; TableRow.children["ping"].children[0].children[0].innerHTML = PING_10010 + "%💻" + PING_189 + "%💻" + PING_10086 + "%"; - // Custom - if (result.servers[i].custom) { - ExpandRow[0].children["expand_custom"].innerHTML = result.servers[i].custom - } else { - ExpandRow[0].children["expand_custom"].innerHTML = "" - } + // monitor + MableRow.children["monitor_text"].innerHTML = result.servers[i].custom; } }; @@ -286,9 +308,12 @@ function uptime() { if (!error) { $("#servers > tr.accordion-toggle").each(function(i) { var TableRow = $("#servers tr#r" + i)[0]; + var MableRow = $("#monitors tr#r" + i)[0]; var ExpandRow = $("#servers #rt" + i); TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-error"; TableRow.children["online_status"].children[0].children[0].innerHTML = "错误"; + MableRow.children["monitor_status"].children[0].children[0].className = "progress-bar progress-bar-error"; + MableRow.children["monitor_status"].children[0].children[0].innerHTML = "错误"; TableRow.children["month_traffic"].children[0].children[0].className = "progress-bar progress-bar-error"; TableRow.children["month_traffic"].children[0].children[0].innerHTML = "错误"; TableRow.children["uptime"].children[0].children[0].className = "progress-bar progress-bar-error"; @@ -311,10 +336,13 @@ function uptime() { TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-error"; TableRow.children["ping"].children[0].children[0].style.width = "100%"; TableRow.children["ping"].children[0].children[0].innerHTML = "错误"; + MableRow.children["monitor_text"].children[0].children[0].className = "progress-bar progress-bar-error"; + MableRow.children["monitor_text"].children[0].children[0].innerHTML = "错误"; if(ExpandRow.hasClass("in")) { ExpandRow.collapse("hide"); } TableRow.setAttribute("data-target", ""); + MableRow.setAttribute("data-target", ""); server_status[i] = false; }); } From 7e46b1062e49225a324726a3a9c3cac600430b8f Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 21 Jan 2024 21:34:07 +0800 Subject: [PATCH 091/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=EF=BC=8C=E6=AF=94=E8=BE=83=E7=B2=97=E7=B3=99=E4=B8=8D=E5=BB=BA?= =?UTF-8?q?=E8=AE=AE=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/client-linux.py | 4 +++- clients/client-psutil.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 05744530..4d79bed1 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -3,6 +3,7 @@ # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures +# ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测间隔60s,记录7天(10080);探测时间30s,记录24小时(2880) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" @@ -17,6 +18,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 +ONLINE_PACKET_HISTORY_LEN = 1440 INTERVAL = 1 import socket @@ -319,7 +321,7 @@ def get_realtime_data(): def _monitor_thread(name, host, interval, type): lostPacket = 0 - packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN) + packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN) while True: if name not in monitorServer.keys(): monitorServer[name] = { diff --git a/clients/client-psutil.py b/clients/client-psutil.py index c2b39281..d468fcbd 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -4,6 +4,7 @@ # 依赖于psutil跨平台库 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures +# ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测时间60s,记录7天在线率(10080);探测时间30s,记录24小时(2880) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" @@ -18,6 +19,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 +ONLINE_PACKET_HISTORY_LEN = 1440 INTERVAL = 1 import socket @@ -307,7 +309,7 @@ def get_realtime_data(): def _monitor_thread(name, host, interval, type): lostPacket = 0 - packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN) + packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN) while True: if name not in monitorServer.keys(): monitorServer[name] = { From 144987bcf119e5c6c462b9cd55e462cec0bbd259 Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 21 Jan 2024 22:55:07 +0800 Subject: [PATCH 092/144] .2f --- clients/client-linux.py | 2 +- clients/client-psutil.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 4d79bed1..9f3e3151 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -520,7 +520,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100}%" for k, v in monitorServer.items()) + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.2f}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise diff --git a/clients/client-psutil.py b/clients/client-psutil.py index d468fcbd..4e9c1f6f 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -510,7 +510,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100}%" for k, v in monitorServer.items()) + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.2f}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise From 94708c588cab6ec3cb18df78b7d70220b5f7091c Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 22 Jan 2024 15:21:06 +0800 Subject: [PATCH 093/144] css resize --- web/css/dark.css | 44 +++++++++++++++++++------------------------- web/css/light.css | 44 +++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 50 deletions(-) diff --git a/web/css/dark.css b/web/css/dark.css index eea98f36..0d6881c9 100644 --- a/web/css/dark.css +++ b/web/css/dark.css @@ -20,35 +20,29 @@ tr.odd.expandRow > :hover { background: #212e36 !important; } #month_traffic { min-width: 85px; max-width: 95px;} #network { min-width: 110px; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } -#ping { max-width: 110px; } +#ping { max-width: 115px; } @media only screen and (max-width: 1200px) { - #server { - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } @media only screen and (max-width: 720px) { - #server { - body { font-size: 10px; } - .content { padding: 0; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + body { font-size: 10px; } + .content { padding: 0; } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } @media only screen and (max-width: 620px) { - #server { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + body { font-size: 10px; } + .content { padding: 0; } + #month_traffic { display:none; visibility:hidden; } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } \ No newline at end of file diff --git a/web/css/light.css b/web/css/light.css index 37e7f775..811c8d09 100644 --- a/web/css/light.css +++ b/web/css/light.css @@ -17,35 +17,29 @@ tr.odd.expandRow > :hover { background: #FFF !important; } #month_traffic { min-width: 85px; max-width: 95px;} #network { min-width: 110px; } #cpu, #ram, #hdd { min-width: 45px; max-width: 90px; } -#ping { max-width: 110px; } +#ping { max-width: 115px; } @media only screen and (max-width: 1200px) { - #server { - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } @media only screen and (max-width: 720px) { - #server { - body { font-size: 10px; } - .content { padding: 0; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + body { font-size: 10px; } + .content { padding: 0; } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } @media only screen and (max-width: 620px) { - #server { - body { font-size: 10px; } - .content { padding: 0; } - #month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; } - #type, tr td:nth-child(4) { display:none; visibility:hidden; } - #location, tr td:nth-child(5) { display:none; visibility:hidden; } - #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } - #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } - #ping, tr td:nth-child(13) { display:none; visibility:hidden; } - } + body { font-size: 10px; } + .content { padding: 0; } + #month_traffic { display:none; visibility:hidden; } + #type { display:none; visibility:hidden; } + #location, tr td:nth-child(5) { display:none; visibility:hidden; } + #uptime, tr td:nth-child(6) { display:none; visibility:hidden; } + #traffic, tr td:nth-child(9) { display:none; visibility:hidden; } + #ping, tr td:nth-child(13) { display:none; visibility:hidden; } } \ No newline at end of file From 6ab046be51683c064bf38a97e5236e184d9b9378 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 22 Jan 2024 15:32:20 +0800 Subject: [PATCH 094/144] update --- clients/client-linux.py | 4 ++-- clients/client-psutil.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 9f3e3151..8de029df 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -18,7 +18,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 1440 +ONLINE_PACKET_HISTORY_LEN = 10080 INTERVAL = 1 import socket @@ -520,7 +520,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.2f}%" for k, v in monitorServer.items()) + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.1f}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 4e9c1f6f..4946a452 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -19,7 +19,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 1440 +ONLINE_PACKET_HISTORY_LEN = 10080 INTERVAL = 1 import socket @@ -510,7 +510,7 @@ def byte_str(object): array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") - array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.2f}%" for k, v in monitorServer.items()) + array['custom'] = "
".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: {v['online_rate']*100:.2f}%" for k, v in monitorServer.items()) s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise From 03446b8f29a1d5e6d4998281439aed12b170d587 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 22 Jan 2024 15:34:44 +0800 Subject: [PATCH 095/144] update some for cl --- clients/client-linux.py | 2 -- clients/client-psutil.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 8de029df..8ebb3270 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -509,8 +509,6 @@ def byte_str(object): array['network_tx'] = netSpeed.get("nettx") array['network_in'] = NET_IN array['network_out'] = NET_OUT - # todo:兼容旧版本,下个版本删除ip_status - array['ip_status'] = True array['ping_10010'] = lostRate.get('10010') * 100 array['ping_189'] = lostRate.get('189') * 100 array['ping_10086'] = lostRate.get('10086') * 100 diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 4946a452..278db936 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -499,8 +499,6 @@ def byte_str(object): array['network_tx'] = netSpeed.get("nettx") array['network_in'] = NET_IN array['network_out'] = NET_OUT - # todo:兼容旧版本,下个版本删除ip_status - array['ip_status'] = True array['ping_10010'] = lostRate.get('10010') * 100 array['ping_189'] = lostRate.get('189') * 100 array['ping_10086'] = lostRate.get('10086') * 100 From 8dfc6d4718fe209ea9160401d0e6e489e60c3eca Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 22 Jan 2024 19:49:29 +0800 Subject: [PATCH 096/144] update --- clients/client-linux.py | 1 + clients/client-psutil.py | 1 + 2 files changed, 2 insertions(+) diff --git a/clients/client-linux.py b/clients/client-linux.py index 8ebb3270..5a6bd1ca 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -455,6 +455,7 @@ def byte_str(object): if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) + monitorServer.clear() for i in data.split('\n'): if "monitor" in i and "type" in i and "{" in i and "}" in i: jdata = json.loads(i[i.find("{"):i.find("}")+1]) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 278db936..da871b88 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -444,6 +444,7 @@ def byte_str(object): if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) + monitorServer.clear() for i in data.split('\n'): if "monitor" in i and "type" in i and "{" in i and "}" in i: jdata = json.loads(i[i.find("{"):i.find("}")+1]) From eddf37c413667dc46b32d6845b33522ba6ae361f Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 10:30:43 +0800 Subject: [PATCH 097/144] fix bug --- clients/client-linux.py | 17 ++++++++++------- clients/client-psutil.py | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 5a6bd1ca..fc65827a 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -324,13 +324,7 @@ def _monitor_thread(name, host, interval, type): packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN) while True: if name not in monitorServer.keys(): - monitorServer[name] = { - "type": type, - "dns_time": 0, - "connect_time": 0, - "download_time": 0, - "online_rate": 1 - } + break if packet_queue.full(): if packet_queue.get() == 0: lostPacket -= 1 @@ -459,6 +453,13 @@ def byte_str(object): for i in data.split('\n'): if "monitor" in i and "type" in i and "{" in i and "}" in i: jdata = json.loads(i[i.find("{"):i.find("}")+1]) + monitorServer[jdata.get("name")] = { + "type": jdata.get("type"), + "dns_time": 0, + "connect_time": 0, + "download_time": 0, + "online_rate": 1 + } t = threading.Thread( target=_monitor_thread, kwargs={ @@ -524,11 +525,13 @@ def byte_str(object): except KeyboardInterrupt: raise except socket.error: + monitorServer.clear() print("Disconnected...") if 's' in locals().keys(): del s time.sleep(3) except Exception as e: + monitorServer.clear() print("Caught Exception:", e) if 's' in locals().keys(): del s diff --git a/clients/client-psutil.py b/clients/client-psutil.py index da871b88..bcb8ea0a 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -312,13 +312,7 @@ def _monitor_thread(name, host, interval, type): packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN) while True: if name not in monitorServer.keys(): - monitorServer[name] = { - "type": type, - "dns_time": 0, - "connect_time": 0, - "download_time": 0, - "online_rate": 1 - } + break if packet_queue.full(): if packet_queue.get() == 0: lostPacket -= 1 @@ -444,10 +438,16 @@ def byte_str(object): if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) - monitorServer.clear() for i in data.split('\n'): if "monitor" in i and "type" in i and "{" in i and "}" in i: jdata = json.loads(i[i.find("{"):i.find("}")+1]) + monitorServer[jdata.get("name")] = { + "type": jdata.get("type"), + "dns_time": 0, + "connect_time": 0, + "download_time": 0, + "online_rate": 1 + } t = threading.Thread( target=_monitor_thread, kwargs={ @@ -514,11 +514,13 @@ def byte_str(object): except KeyboardInterrupt: raise except socket.error: + monitorServer.clear() print("Disconnected...") if 's' in locals().keys(): del s time.sleep(3) except Exception as e: + monitorServer.clear() print("Caught Exception:", e) if 's' in locals().keys(): del s From 810f6a0d8a231ba676c46fc6e873d821a43102d9 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 16:47:26 +0800 Subject: [PATCH 098/144] fix --- web/js/serverstatus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/js/serverstatus.js b/web/js/serverstatus.js index 529456c0..02ca72b8 100644 --- a/web/js/serverstatus.js +++ b/web/js/serverstatus.js @@ -91,7 +91,7 @@ function uptime() { } if (!MableRow.length) { $("#monitors").append( - "" + + "" + "
加载中
" + "加载中" + "加载中" + From fb3ecd179651e81d12095e8eafc6bfe5dd9d002f Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 17:43:27 +0800 Subject: [PATCH 099/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=B8=AAtod?= =?UTF-8?q?o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 +++++++++++++++------- server/config.json | 2 +- server/src/main.cpp | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a980f6c8..64b72c1e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ cd ServerStatus/server && make #### 二、修改配置文件 ```diff -! watchdog rule 可以为任何已知字段的表达式 +! watchdog rule 可以为任何已知字段的表达式。注意Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,todo等待修复 ! watchdog interval 最小通知间隔 ! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调 @@ -89,13 +89,21 @@ cd ServerStatus/server && make "location": "🇨🇳", "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 - }, + } + ], + "monitors": [ + { + "name": "百度一下", + "host": "https://www.baidu.com", + "interval": 60, + "type": "https" + } ], "watchdog": [ { - "name": "服务器负载高监控,排除内存大于32G物理机,同时排除俄勒冈机器", - "rule": "cpu>90&load_1>4&memory_total<33554432&name!='俄勒冈'", + "name": "服务器负载高监控,排除内存大于32G物理机,同时排除node1机器", + "rule": "cpu>90&load_1>4&memory_total<33554432&name!='node1'", "interval": 600, "callback": "https://yourSMSurl" }, @@ -106,8 +114,8 @@ cd ServerStatus/server && make "callback": "https://yourSMSurl" }, { - "name": "服务器宕机告警,排出俄勒冈,排除s02", - "rule": "online4=0&online6=0&name!='俄勒冈'&username!='s02'", + "name": "服务器宕机告警,排出node1,排除s02", + "rule": "online4=0&online6=0&name!='node1'&username!='s02'", "interval": 600, "callback": "https://yourSMSurl" }, @@ -124,7 +132,7 @@ cd ServerStatus/server && make "callback": "https://yourSMSurl" }, { - "name": "你可以组合任何已知字段的表达式", + "name": "你可以组合任何已知字段的表达式,注意Exprtk库目前不支持中文等Unicode字符", "rule": "(hdd_used/hdd_total)*100>95", "interval": 1800, "callback": "https://yourSMSurl" diff --git a/server/config.json b/server/config.json index 29a4df47..aea25733 100644 --- a/server/config.json +++ b/server/config.json @@ -46,7 +46,7 @@ "type": "https" }, { - "name": "主机交流", + "name": "502论坛", "host": "https://www.hostloc.com", "interval": 60, "type": "https" diff --git a/server/src/main.cpp b/server/src/main.cpp index 2dc5c434..acada378 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -278,6 +278,23 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl int ID = 0; while (strcmp(Watchdog(ID)->m_aName, "NULL")) { +// Exprtk库默认使用窄字符类型,但可能会出现中文等Unicode字符无法正确解析的问题。 +// todo: 为解决此问题,可以使用宽字符类型替换Exprtk库中默认的窄字符类型。 +// #include +// #include +// #include +// typedef exprtk::expression expression_type; +// typedef exprtk::parser parser_type; +// int main() +// { +// std::wstring expression_string = L"sin(x)"; +// expression_type expression; +// parser_type parser; +// parser.compile(expression_string, expression); +// double x = 3.14; +// double result = expression.value(); +// return 0; +// } typedef exprtk::symbol_table symbol_table_t; typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; From c236aee5dc38a92cf54e133a1b96b7f4b8ea6520 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 17:52:59 +0800 Subject: [PATCH 100/144] todo list --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 64b72c1e..c306d974 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ [![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) [![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus) [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) -[![Version](https://img.shields.io/badge/Version-Build%201.1.1-red)](https://github.com/cppla/ServerStatus) +[![Version](https://img.shields.io/badge/Version-Build%201.1.2-red)](https://github.com/cppla/ServerStatus) ![Latest Version](http://dl.cpp.la/Archive/serverstatus_1.0.9.png) -`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。` +`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复 ` # 目录: @@ -67,7 +67,7 @@ cd ServerStatus/server && make #### 二、修改配置文件 ```diff -! watchdog rule 可以为任何已知字段的表达式。注意Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,todo等待修复 +! watchdog rule 可以为任何已知字段的表达式。注意Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复 ! watchdog interval 最小通知间隔 ! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调 @@ -132,7 +132,7 @@ cd ServerStatus/server && make "callback": "https://yourSMSurl" }, { - "name": "你可以组合任何已知字段的表达式,注意Exprtk库目前不支持中文等Unicode字符", + "name": "你可以组合任何已知字段的表达式", "rule": "(hdd_used/hdd_total)*100>95", "interval": 1800, "callback": "https://yourSMSurl" From 1f7827cc211e9b482bd3b8cfcd65c7cb719ff968 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 18:00:24 +0800 Subject: [PATCH 101/144] change --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c306d974..d5e0968a 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ cd ServerStatus/server && make ], "monitors": [ { - "name": "百度一下", + "name": "你可以监测自己的网站以及MySQL、Redis", "host": "https://www.baidu.com", "interval": 60, "type": "https" From 052c75ef23c79557d87c393b2ff483110a0707f7 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 18:09:23 +0800 Subject: [PATCH 102/144] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5e0968a..f44c254a 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ cd ServerStatus/server && make ], "monitors": [ { - "name": "你可以监测自己的网站以及MySQL、Redis", + "name": "监测网站以及MySQL、Redis,默认为七天在线率", "host": "https://www.baidu.com", "interval": 60, "type": "https" From aa0ccd254c156931ca607059504958b861dd5aec Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 23 Jan 2024 18:50:15 +0800 Subject: [PATCH 103/144] update readme --- README.md | 5 +++-- server/config.json | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f44c254a..9026efd7 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) [![Version](https://img.shields.io/badge/Version-Build%201.1.2-red)](https://github.com/cppla/ServerStatus) -![Latest Version](http://dl.cpp.la/Archive/serverstatus_1.0.9.png) +![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_host.png) +![Latest Server Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_server.png) -`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复 ` +`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复。 ` # 目录: diff --git a/server/config.json b/server/config.json index aea25733..f3f0e40a 100644 --- a/server/config.json +++ b/server/config.json @@ -40,19 +40,19 @@ ], "monitors": [ { - "name": "百度一下", + "name": "baidu", "host": "https://www.baidu.com", "interval": 60, "type": "https" }, { - "name": "502论坛", + "name": "502BBS", "host": "https://www.hostloc.com", "interval": 60, "type": "https" }, { - "name": "DNS服务", + "name": "myDNS", "host": "114.114.114.114:53", "interval": 60, "type": "tcp" From 75d06c86660f124dd41cbee3690b1b29db0cf7cd Mon Sep 17 00:00:00 2001 From: cppla Date: Sat, 27 Jan 2024 15:27:10 +0800 Subject: [PATCH 104/144] add some ua --- clients/client-linux.py | 4 ++-- clients/client-psutil.py | 4 ++-- server/config.json | 8 +------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index fc65827a..5b1520d3 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -341,7 +341,7 @@ def _monitor_thread(name, host, interval, type): k = socket.create_connection((IP, 80), timeout=6) monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) m = timeit.default_timer() - k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) response = b"" while True: data = k.recv(4096) @@ -367,7 +367,7 @@ def _monitor_thread(name, host, interval, type): monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) m = timeit.default_timer() kk = context.wrap_socket(k, server_hostname=address) - kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) response = b"" while True: data = kk.recv(4096) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index bcb8ea0a..3b566d8b 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -329,7 +329,7 @@ def _monitor_thread(name, host, interval, type): k = socket.create_connection((IP, 80), timeout=6) monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) m = timeit.default_timer() - k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) response = b"" while True: data = k.recv(4096) @@ -355,7 +355,7 @@ def _monitor_thread(name, host, interval, type): monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000) m = timeit.default_timer() kk = context.wrap_socket(k, server_hostname=address) - kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) + kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8')) response = b"" while True: data = kk.recv(4096) diff --git a/server/config.json b/server/config.json index f3f0e40a..9122e5e3 100644 --- a/server/config.json +++ b/server/config.json @@ -46,13 +46,7 @@ "type": "https" }, { - "name": "502BBS", - "host": "https://www.hostloc.com", - "interval": 60, - "type": "https" - }, - { - "name": "myDNS", + "name": "114", "host": "114.114.114.114:53", "interval": 60, "type": "tcp" From dc3868998a9a3cdcfb6a821ee22cbe3274e65532 Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 4 Feb 2024 14:37:39 +0800 Subject: [PATCH 105/144] 256->512 --- server/src/network.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/network.h b/server/src/network.h index 920d36f4..49187f85 100644 --- a/server/src/network.h +++ b/server/src/network.h @@ -10,7 +10,7 @@ enum NET_CONNSTATE_ERROR=4, NET_MAX_PACKETSIZE = 1400, - NET_MAX_CLIENTS = 256 + NET_MAX_CLIENTS = 512 }; typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser); From a8b9b2d00d6dab6975e9842e750d7b9ea1a82aca Mon Sep 17 00:00:00 2001 From: cppla Date: Sun, 4 Feb 2024 14:43:19 +0800 Subject: [PATCH 106/144] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=80=E5=A4=A9?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/client-linux.py | 4 ++-- clients/client-psutil.py | 4 ++-- server/config.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 5b1520d3..c014229b 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -3,7 +3,7 @@ # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures -# ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测间隔60s,记录7天(10080);探测时间30s,记录24小时(2880) +# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间180s,记录24小时(480);探测间隔60s,记录7天(10080) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" @@ -18,7 +18,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 10080 +ONLINE_PACKET_HISTORY_LEN = 480 INTERVAL = 1 import socket diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 3b566d8b..19743e75 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -4,7 +4,7 @@ # 依赖于psutil跨平台库 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures -# ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测时间60s,记录7天在线率(10080);探测时间30s,记录24小时(2880) +# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间180s,记录24小时(480);探测间隔60s,记录7天(10080) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" @@ -19,7 +19,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 10080 +ONLINE_PACKET_HISTORY_LEN = 480 INTERVAL = 1 import socket diff --git a/server/config.json b/server/config.json index 9122e5e3..f9c13766 100644 --- a/server/config.json +++ b/server/config.json @@ -42,13 +42,13 @@ { "name": "baidu", "host": "https://www.baidu.com", - "interval": 60, + "interval": 180, "type": "https" }, { "name": "114", "host": "114.114.114.114:53", - "interval": 60, + "interval": 180, "type": "tcp" } ], From 25f878a38a3a8a15bcd9d3ef91deeda8cb208588 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 11 Mar 2024 15:03:57 +0800 Subject: [PATCH 107/144] =?UTF-8?q?5=E5=88=86=E9=92=9F=E4=B8=80=E6=AC=A1pr?= =?UTF-8?q?obe=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/client-linux.py | 2 +- clients/client-psutil.py | 2 +- server/config.json | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index c014229b..7d9e4b5d 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -3,7 +3,7 @@ # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures -# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间180s,记录24小时(480);探测间隔60s,记录7天(10080) +# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间300s,记录24小时(288);探测间隔60s,记录7天(10080) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 19743e75..42a9d9bb 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -4,7 +4,7 @@ # 依赖于psutil跨平台库 # 版本:1.0.3, 支持Python版本:2.7 to 3.10 # 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures -# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间180s,记录24小时(480);探测间隔60s,记录7天(10080) +# ONLINE_PACKET_HISTORY_LEN, 探测间隔120s,记录24小时在线率(720);探测时间300s,记录24小时(288);探测间隔60s,记录7天(10080) # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。 SERVER = "127.0.0.1" diff --git a/server/config.json b/server/config.json index f9c13766..de79f188 100644 --- a/server/config.json +++ b/server/config.json @@ -42,13 +42,19 @@ { "name": "baidu", "host": "https://www.baidu.com", - "interval": 180, + "interval": 300, + "type": "https" + }, + { + "name": "aliyun", + "host": "https://www.aliyun.com", + "interval": 300, "type": "https" }, { "name": "114", "host": "114.114.114.114:53", - "interval": 180, + "interval": 300, "type": "tcp" } ], From 6331d7d45b9bf861e06ab7aaa3118a7573697f23 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 11 Mar 2024 15:06:47 +0800 Subject: [PATCH 108/144] update --- clients/client-linux.py | 2 +- clients/client-psutil.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 7d9e4b5d..a9d5dc2a 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -18,7 +18,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 480 +ONLINE_PACKET_HISTORY_LEN = 288 INTERVAL = 1 import socket diff --git a/clients/client-psutil.py b/clients/client-psutil.py index 42a9d9bb..d3038095 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -19,7 +19,7 @@ PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 -ONLINE_PACKET_HISTORY_LEN = 480 +ONLINE_PACKET_HISTORY_LEN = 288 INTERVAL = 1 import socket From f91279406876846c6c5fe5cd6e5c17aad44ecc46 Mon Sep 17 00:00:00 2001 From: cppla Date: Tue, 2 Apr 2024 10:24:12 +0800 Subject: [PATCH 109/144] add todo --- server/src/main.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index acada378..9eb6a4a9 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -110,13 +110,6 @@ void CMain::OnDelClient(int ClientNetID) { int ClientID = ClientNetToClient(ClientNetID); dbg_msg("main", "OnDelClient(ncid=%d, cid=%d)", ClientNetID, ClientID); - //copy offline message for watchdog - WatchdogMessage(ClientNetID, - 0, 0, 0, 0, 0, 0, - 0, 0, 0,0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0,0, 0, 0, - 0, 0, 0, 0); if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS) { Client(ClientID)->m_Connected = false; @@ -124,6 +117,13 @@ void CMain::OnDelClient(int ClientNetID) Client(ClientID)->m_ClientNetType = NETTYPE_INVALID; mem_zero(&Client(ClientID)->m_Stats, sizeof(CClient::CStats)); } + //copy offline message for watchdog + WatchdogMessage(ClientNetID, + 0, 0, 0, 0, 0, 0, + 0, 0, 0,0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0,0, 0, 0, + 0, 0, 0, 0); } int CMain::HandleMessage(int ClientNetID, char *pMessage) @@ -353,6 +353,11 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl time_t currentStamp = (long long)time(/*ago*/0); if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) { + if (!Client(ClientID)->m_Stats.m_Online4 && !Client(ClientID)->m_Stats.m_Online6) + { + //休眠5分钟如果5分钟后状态发生了变更,消息不发出。 + printf("download\n"); + } Client(ClientID)->m_AlarmLastTime = currentStamp; CURL *curl; CURLcode res; From 388938e02bf33ce9a5cf329b93a2015cb4ccd9d8 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 16:39:08 +0800 Subject: [PATCH 110/144] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=BA=86=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E9=97=AA=E6=96=AD=E5=AF=BC=E8=87=B4=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=8A=A5=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main.cpp | 110 +++++++++++++++++++++++++++++++++++++++++--- server/src/main.h | 4 +- 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 9eb6a4a9..743fe916 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -117,13 +117,9 @@ void CMain::OnDelClient(int ClientNetID) Client(ClientID)->m_ClientNetType = NETTYPE_INVALID; mem_zero(&Client(ClientID)->m_Stats, sizeof(CClient::CStats)); } - //copy offline message for watchdog - WatchdogMessage(ClientNetID, - 0, 0, 0, 0, 0, 0, - 0, 0, 0,0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0,0, 0, 0, - 0, 0, 0, 0); + m_OfflineAlarmThreadData.pClients = m_aClients; + m_OfflineAlarmThreadData.pWatchDogs = m_aCWatchDogs; + thread_create(offlineAlarmThread, &m_OfflineAlarmThreadData); } int CMain::HandleMessage(int ClientNetID, char *pMessage) @@ -503,6 +499,105 @@ void CMain::JSONUpdateThread(void *pUser) fs_rename(pConfig->m_aJSONFile, aJSONFileTmp); } +void CMain::offlineAlarmThread(void *pUser) +{ + CJSONUpdateThreadData *m_OfflineAlarmThreadData = (CJSONUpdateThreadData *)pUser; + CClient *pClients = m_OfflineAlarmThreadData->pClients; + CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs; + thread_sleep(6000); + if(!pClients->m_Connected) + { + int ID = 0; + while (strcmp(pWatchDogs[ID].m_aName, "NULL")) + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + const std::string expression_string = pWatchDogs[ID].m_aRule; + std::string username = pClients->m_aUsername; + std::string name = pClients->m_aName; + std::string type = pClients->m_aType; + std::string host = pClients->m_aHost; + std::string location = pClients->m_aLocation; + std::double_t online4 = pClients->m_Stats.m_Online4; + std::double_t online6 = pClients->m_Stats.m_Online6; + + symbol_table_t symbol_table; + symbol_table.add_stringvar("username", username); + symbol_table.add_stringvar("name", name); + symbol_table.add_stringvar("type", type); + symbol_table.add_stringvar("host", host); + symbol_table.add_stringvar("location", location); + symbol_table.add_variable("online4",online4); + symbol_table.add_variable("online6",online6); + symbol_table.add_constants(); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + if (expression.value() > 0) + { + time_t currentStamp = (long long)time(/*ago*/0); + if ((currentStamp-pClients->m_AlarmLastTime) > pWatchDogs[ID].m_aInterval) + { + printf("客户端下线, Client disconnects and sends alert information\n"); + pClients->m_AlarmLastTime = currentStamp; + CURL *curl; + CURLcode res; + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + //standard time + char standardTime[32]= { 0 }; + strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(¤tStamp)); + + //url encode, Rules conflict with url special characters,eg:&, del rules, by https://cpp.la, 2023-10-09 + char encodeBuffer[2048] = { 0 }; + sprintf(encodeBuffer, "【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", + pWatchDogs[ID].m_aName, + standardTime, + pClients->m_aUsername, + pClients->m_aName, + pClients->m_aType, + pClients->m_aHost, + pClients->m_aLocation); + char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer)); + + //standard url + char urlBuffer[2048] = { 0 }; + sprintf(urlBuffer, "%s%s",pWatchDogs[ID].m_aCallback, encodeUrl); + + + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"signature=ServerStatus"); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "watchdog failed: %s\n", curl_easy_strerror(res)); + if(encodeUrl) + curl_free(encodeUrl); + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + } + } + ID++; + } + } + else + { + printf("网络波动,No alarm information is sent due to network fluctuations\n"); + } +} + int CMain::ReadConfig() { // read and parse config @@ -701,6 +796,7 @@ int CMain::Run() m_JSONUpdateThreadData.m_ReloadRequired = 2; m_JSONUpdateThreadData.pClients = m_aClients; m_JSONUpdateThreadData.pConfig = &m_Config; + m_JSONUpdateThreadData.pWatchDogs = m_aCWatchDogs; void *LoadThread = thread_create(JSONUpdateThread, &m_JSONUpdateThreadData); //thread_detach(LoadThread); diff --git a/server/src/main.h b/server/src/main.h index 848d2468..36496613 100644 --- a/server/src/main.h +++ b/server/src/main.h @@ -101,10 +101,12 @@ class CMain { CClient *pClients; CConfig *pConfig; + CWatchDog *pWatchDogs; volatile short m_ReloadRequired; - } m_JSONUpdateThreadData; + } m_JSONUpdateThreadData, m_OfflineAlarmThreadData; static void JSONUpdateThread(void *pUser); + static void offlineAlarmThread(void *pUser); public: CMain(CConfig Config); From fdc5abacfcf7cff44ecdfdebf05ffb559f7444fd Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 16:42:40 +0800 Subject: [PATCH 111/144] fix bug for offline --- README.md | 6 +++--- server/config.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9026efd7..fe7b0059 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) [![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus) [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) -[![Version](https://img.shields.io/badge/Version-Build%201.1.2-red)](https://github.com/cppla/ServerStatus) +[![Version](https://img.shields.io/badge/Version-Build%201.1.3-red)](https://github.com/cppla/ServerStatus) ![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_host.png) ![Latest Server Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_server.png) @@ -115,8 +115,8 @@ cd ServerStatus/server && make "callback": "https://yourSMSurl" }, { - "name": "服务器宕机告警,排出node1,排除s02", - "rule": "online4=0&online6=0&name!='node1'&username!='s02'", + "name": "服务器宕机告警", + "rule": "online4=0&online6=0", "interval": 600, "callback": "https://yourSMSurl" }, diff --git a/server/config.json b/server/config.json index de79f188..0a960568 100644 --- a/server/config.json +++ b/server/config.json @@ -72,8 +72,8 @@ "callback": "https://yourSMSurl" }, { - "name": "offline warning,exclude name node1", - "rule": "online4=0&online6=0&name!='node1'", + "name": "offline warning", + "rule": "online4=0&online6=0", "interval": 600, "callback": "https://yourSMSurl" }, From 91f11dad760d6b3e6201024f6c3dd7da644eda9a Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 17:16:32 +0800 Subject: [PATCH 112/144] =?UTF-8?q?=E5=B1=8F=E8=94=BD=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E7=9A=84nginx=E6=97=A5=E5=BF=97=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5wq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d9f0a01..1228fcb3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN pwd && ls -a # glibc env run FROM nginx:latest -RUN mkdir -p /ServerStatus/server/ +RUN mkdir -p /ServerStatus/server/ && ln -sf /dev/null /var/log/nginx/access.log && ln -sf /dev/null /var/log/nginx/error.log COPY --from=builder server /ServerStatus/server/ COPY --from=builder web /usr/share/nginx/html/ @@ -25,5 +25,5 @@ ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone EXPOSE 80 35601 - +HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl --fail http://localhost:80 || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)' CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html' From d75d5438a3f58f3ea4a19b2a73238fcf3c00d37a Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 17:44:43 +0800 Subject: [PATCH 113/144] docker compose healthcheck --- docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 47011997..5b935d20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,11 @@ services: context: . dockerfile: Dockerfile image: serverstatus_server + healthcheck: + test: curl --fail http://localhost:80 || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)' + interval: 30s + timeout: 10s + retries: 5 container_name: serverstatus restart: unless-stopped networks: From 503037c7e2d4c1ae20929e8a65615f9ed8837640 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 19:53:04 +0800 Subject: [PATCH 114/144] add two logs --- docker-compose.yml | 1 - server/src/main.cpp | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5b935d20..42f8e12b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,6 @@ services: networks: serverstatus-network: - name: serverstatus-network ipam: config: - subnet: 172.23.0.0/24 diff --git a/server/src/main.cpp b/server/src/main.cpp index 743fe916..6b318da6 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -543,7 +543,7 @@ void CMain::offlineAlarmThread(void *pUser) time_t currentStamp = (long long)time(/*ago*/0); if ((currentStamp-pClients->m_AlarmLastTime) > pWatchDogs[ID].m_aInterval) { - printf("客户端下线, Client disconnects and sends alert information\n"); + printf("客户端下线且超过阈值, Client disconnects and sends alert information\n"); pClients->m_AlarmLastTime = currentStamp; CURL *curl; CURLcode res; @@ -588,6 +588,8 @@ void CMain::offlineAlarmThread(void *pUser) } curl_global_cleanup(); } + else + printf("客户端下线但未超过阈值,No alarm if the threshold is not exceeded\n"); } ID++; } @@ -596,6 +598,7 @@ void CMain::offlineAlarmThread(void *pUser) { printf("网络波动,No alarm information is sent due to network fluctuations\n"); } + fflush(stdout); } int CMain::ReadConfig() From 510567eaeca5403db3faef9839739140c8f27d14 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 21:31:35 +0800 Subject: [PATCH 115/144] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A9=B4=E5=A4=B4?= =?UTF-8?q?=E4=B8=8D=E5=AF=B9=E9=A9=AC=E5=98=B4=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 6b318da6..9109606b 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -119,6 +119,7 @@ void CMain::OnDelClient(int ClientNetID) } m_OfflineAlarmThreadData.pClients = m_aClients; m_OfflineAlarmThreadData.pWatchDogs = m_aCWatchDogs; + m_OfflineAlarmThreadData.m_ReloadRequired = ClientID; thread_create(offlineAlarmThread, &m_OfflineAlarmThreadData); } @@ -504,8 +505,9 @@ void CMain::offlineAlarmThread(void *pUser) CJSONUpdateThreadData *m_OfflineAlarmThreadData = (CJSONUpdateThreadData *)pUser; CClient *pClients = m_OfflineAlarmThreadData->pClients; CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs; + volatile short ClientID = m_OfflineAlarmThreadData->m_ReloadRequired; thread_sleep(6000); - if(!pClients->m_Connected) + if(!pClients[ClientID].m_Connected) { int ID = 0; while (strcmp(pWatchDogs[ID].m_aName, "NULL")) @@ -514,13 +516,13 @@ void CMain::offlineAlarmThread(void *pUser) typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; const std::string expression_string = pWatchDogs[ID].m_aRule; - std::string username = pClients->m_aUsername; - std::string name = pClients->m_aName; - std::string type = pClients->m_aType; - std::string host = pClients->m_aHost; - std::string location = pClients->m_aLocation; - std::double_t online4 = pClients->m_Stats.m_Online4; - std::double_t online6 = pClients->m_Stats.m_Online6; + std::string username = pClients[ClientID].m_aUsername; + std::string name = pClients[ClientID].m_aName; + std::string type = pClients[ClientID].m_aType; + std::string host = pClients[ClientID].m_aHost; + std::string location = pClients[ClientID].m_aLocation; + std::double_t online4 = pClients[ClientID].m_Stats.m_Online4; + std::double_t online6 = pClients[ClientID].m_Stats.m_Online6; symbol_table_t symbol_table; symbol_table.add_stringvar("username", username); @@ -541,10 +543,10 @@ void CMain::offlineAlarmThread(void *pUser) if (expression.value() > 0) { time_t currentStamp = (long long)time(/*ago*/0); - if ((currentStamp-pClients->m_AlarmLastTime) > pWatchDogs[ID].m_aInterval) + if ((currentStamp-pClients[ClientID].m_AlarmLastTime) > pWatchDogs[ID].m_aInterval) { printf("客户端下线且超过阈值, Client disconnects and sends alert information\n"); - pClients->m_AlarmLastTime = currentStamp; + pClients[ClientID].m_AlarmLastTime = currentStamp; CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_ALL); @@ -560,11 +562,11 @@ void CMain::offlineAlarmThread(void *pUser) sprintf(encodeBuffer, "【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", pWatchDogs[ID].m_aName, standardTime, - pClients->m_aUsername, - pClients->m_aName, - pClients->m_aType, - pClients->m_aHost, - pClients->m_aLocation); + pClients[ClientID].m_aUsername, + pClients[ClientID].m_aName, + pClients[ClientID].m_aType, + pClients[ClientID].m_aHost, + pClients[ClientID].m_aLocation); char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer)); //standard url From 0fe01064a4d281ec663b504ba0d43d9c62b91ca0 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 21:59:23 +0800 Subject: [PATCH 116/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe7b0059..53ef7ba8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_host.png) ![Latest Server Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_server.png) -`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复。 ` +`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复。 ` # 目录: From 4e73e8185ec53626750bad70191feb1d6ba7cc89 Mon Sep 17 00:00:00 2001 From: cppla Date: Wed, 3 Apr 2024 22:06:15 +0800 Subject: [PATCH 117/144] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53ef7ba8..98c54763 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus) [![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus) [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) -[![Version](https://img.shields.io/badge/Version-Build%201.1.3-red)](https://github.com/cppla/ServerStatus) +[![Version](https://img.shields.io/badge/Version-Build%201.1.4-red)](https://github.com/cppla/ServerStatus) ![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_host.png) ![Latest Server Version](https://dl.cpp.la/Archive/serverstatus_1.1.2_server.png) From adb05818b99907dc6731b546e3512124d94228c7 Mon Sep 17 00:00:00 2001 From: cppla Date: Mon, 8 Apr 2024 14:25:53 +0800 Subject: [PATCH 118/144] =?UTF-8?q?=E6=94=B9=E4=B8=BA15=E7=A7=92=E5=86=8D?= =?UTF-8?q?=E6=AC=A1=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E7=A6=BB=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index 9109606b..bec8ae65 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -506,7 +506,7 @@ void CMain::offlineAlarmThread(void *pUser) CClient *pClients = m_OfflineAlarmThreadData->pClients; CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs; volatile short ClientID = m_OfflineAlarmThreadData->m_ReloadRequired; - thread_sleep(6000); + thread_sleep(15000); if(!pClients[ClientID].m_Connected) { int ID = 0; From 08f15ebdc5499347592da4a72d2e8342e114b677 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 18 Apr 2024 15:34:43 +0800 Subject: [PATCH 119/144] 15s -> 25s --- server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main.cpp b/server/src/main.cpp index bec8ae65..cc239e40 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -506,7 +506,7 @@ void CMain::offlineAlarmThread(void *pUser) CClient *pClients = m_OfflineAlarmThreadData->pClients; CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs; volatile short ClientID = m_OfflineAlarmThreadData->m_ReloadRequired; - thread_sleep(15000); + thread_sleep(25000); if(!pClients[ClientID].m_Connected) { int ID = 0; From d9e8f8a7c12bc948198e4529255c7e565240c786 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 15 Aug 2024 14:02:33 +0800 Subject: [PATCH 120/144] del ie --- web/index.html | 5 - web/js/html5shiv.js | 326 ------------------------------------------ web/js/respond.min.js | 5 - 3 files changed, 336 deletions(-) delete mode 100644 web/js/html5shiv.js delete mode 100644 web/js/respond.min.js diff --git a/web/index.html b/web/index.html index 5fa61757..4b46318f 100644 --- a/web/index.html +++ b/web/index.html @@ -26,11 +26,6 @@ padding-bottom: 30px; } - -