diff --git a/exprtk.hpp b/exprtk.hpp index 9e9b913..e04e4c3 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -46,6 +46,7 @@ #include #include #include +#include namespace exprtk @@ -224,7 +225,7 @@ namespace exprtk static const std::string reserved_words[] = { "and", "false", "for", "if", "ilike", "in", "like", "nand", "nor", "not", - "null", "or", "shl", "shr", "true", "while", "xor" + "null", "or", "shl", "shr", "true", "while", "xnor", "xor" }; static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); @@ -237,7 +238,7 @@ namespace exprtk "in", "inrange", "like", "log", "log10", "logn", "log1p", "max", "min", "mod", "mul", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", "root", "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", - "sum", "tan", "tanh", "true", "trunc", "while", "xor" + "sum", "tan", "tanh", "true", "trunc", "while", "xnor", "xor" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -403,6 +404,18 @@ namespace exprtk #undef exprtk_register_real_type_tag #undef exprtk_register_int_type_tag + template + inline bool is_true_impl(const T v) + { + return (v != T(0)); + } + + template + inline bool is_false_impl(const T v) + { + return (v == T(0)); + } + template inline T equal_impl(const T v0, const T v1, real_type_tag) { @@ -610,6 +623,28 @@ namespace exprtk 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); + } + template inline T erf_impl(T v, real_type_tag) { @@ -821,6 +856,13 @@ namespace exprtk return details::xor_impl(v0,v1,num_type); } + template + inline T xnor_opr(const T v0, const T v1) + { + typename details::number_type::type num_type; + return details::xnor_impl(v0,v1,num_type); + } + template inline bool is_integer(const T v) { @@ -2643,18 +2685,19 @@ namespace exprtk 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_shr , - e_shl , e_abs , e_acos , e_asin , - e_atan , e_ceil , e_cos , e_cosh , - e_exp , e_floor , e_log , e_log10 , - e_log1p , e_logn , e_neg , e_pos , - e_round , e_roundn , e_root , e_sqrt , - e_sin , e_sinh , e_sec , e_csc , - e_tan , e_tanh , e_cot , e_clamp , - e_inrange, e_sgn , e_r2d , e_d2r , - e_d2g , e_g2d , e_hypot , e_notl , - e_erf , e_erfc , e_frac , e_trunc , - e_assign , e_in , e_like , e_ilike , + e_or , e_nor , e_xor , e_xnor , + e_shr , e_shl , e_abs , e_acos , + e_asin , e_atan , e_ceil , e_cos , + e_cosh , e_exp , e_floor , e_log , + e_log10 , e_log1p , e_logn , e_neg , + e_pos , e_round , e_roundn , e_root , + e_sqrt , e_sin , e_sinh , e_sec , + e_csc , e_tan , e_tanh , e_cot , + e_clamp , e_inrange, e_sgn , e_r2d , + e_d2r , e_d2g , e_g2d , e_hypot , + e_notl , e_erf , e_erfc , e_frac , + e_trunc , e_assign , e_in , e_like , + e_ilike , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -2692,7 +2735,8 @@ namespace exprtk 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_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, + e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043 }; struct base_operation_t @@ -2797,6 +2841,7 @@ namespace exprtk 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) ? T(1) : T(0); + case e_xnor : return (arg0 != arg1) ? T(0) : T(1); case e_root : return root(arg0,arg1); case e_roundn : return roundn(arg0,arg1); case e_equal : return equal(arg0,arg1); @@ -2836,6 +2881,7 @@ namespace exprtk 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; @@ -2880,22 +2926,23 @@ namespace exprtk 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_in , e_like , e_ilike , - e_inranges , e_ipow , e_ipowinv , e_abs , - e_acos , e_asin , e_atan , e_ceil , - e_cos , e_cosh , e_exp , e_floor , - e_log , e_log10 , e_log1p , e_neg , - e_pos , e_round , e_sin , 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_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_xor , e_xnor , e_in , e_like , + e_ilike , e_inranges , e_ipow , e_ipowinv , + e_abs , e_acos , e_asin , e_atan , + e_ceil , e_cos , e_cosh , e_exp , + e_floor , e_log , e_log10 , e_log1p , + e_neg , e_pos , e_round , e_sin , + 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_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 }; typedef T value_type; @@ -3906,6 +3953,11 @@ namespace exprtk template struct sfext37_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) / (z - w); } static inline std::string id() { return "(t/t)/(t-t)";} }; template struct sfext38_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z - w); } static inline std::string id() { return "(t*t)*(t-t)";} }; template struct sfext39_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) * (z - w); } static inline std::string id() { return "(t/t)*(t-t)";} }; + template struct sfext40_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y * (z / w)); } static inline std::string id() { return "t+(t*(t/t))";} }; + template struct sfext41_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y * (z / w)); } static inline std::string id() { return "t-(t*(t/t))";} }; + template struct sfext42_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} }; + template struct sfext43_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} }; + template class sf3_node : public trinary_node @@ -4601,6 +4653,15 @@ namespace exprtk 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 { @@ -4776,6 +4837,8 @@ namespace exprtk public: virtual std::string type_id() const = 0; + + virtual std::string type_id2() const { return ""; } }; template @@ -5505,8 +5568,20 @@ namespace exprtk const tfunc_t f_; }; + template + class sf3ext_type_node : public T0oT1oT2_base_node + { + public: + + virtual T0 t0() const = 0; + + virtual T1 t1() const = 0; + + virtual T2 t2() const = 0; + }; + template - class T0oT1oT2_sf3ext : public T0oT1oT2_base_node + class T0oT1oT2_sf3ext : public sf3ext_type_node { public: @@ -5537,17 +5612,17 @@ namespace exprtk return SF3Operation::process(t0_,t1_,t2_); } - inline T0 t0() const + T0 t0() const { return t0_; } - inline T1 t1() const + T1 t1() const { return t1_; } - inline T2 t2() const + T2 t2() const { return t2_; } @@ -5557,6 +5632,30 @@ namespace exprtk return id(); } + std::string type_id2() const + { + std::string t[] = { + param_to_str::result>::result(), + param_to_str::result>::result(), + param_to_str::result>::result() + }; + + std::string sf3id = id(); + + for (std::size_t i = 0; i < 3; ++i) + { + std::size_t index = std::string::npos; + if (std::string::npos != (index = sf3id.find("t"))) + { + sf3id[index] = t[i][0]; + } + else + break; + } + + return sf3id; + } + static inline std::string id() { return SF3Operation::id(); @@ -5578,6 +5677,20 @@ namespace exprtk 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 : public T0oT1oT2_base_node { @@ -5745,6 +5858,24 @@ namespace exprtk 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 { @@ -5757,6 +5888,7 @@ namespace exprtk 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 @@ -6819,11 +6951,118 @@ namespace exprtk { private: + 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); + } + + protected: + + virtual value_ptr value_at(const std::size_t&) const = 0; + + }; + + class array_vector_impl : public vector_holder_base + { + public: + + array_vector_impl(const T* 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); + } + + private: + + array_vector_impl operator=(const array_vector_impl&); + + const T* 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); + } + + private: + + sequence_vector_impl operator=(const sequence_vector_impl&); + + sequence_t& sequence_; + }; + + public: + + vector_holder(Type* vec, const std::size_t& vec_size) + : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) + {} + + template + vector_holder(std::vector& vec) + : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) + {} + + template + vector_holder(std::deque& deq) + : vector_holder_base_(new(buffer)sequence_vector_impl(deq)) + {} + + inline value_ptr operator[](const std::size_t& index) const + { + return (*vector_holder_base_)[index]; + } + + private: + + mutable vector_holder_base* vector_holder_base_; + unsigned char buffer[64]; + }; + template struct type_store { typedef typename details::variable_node variable_node_t; typedef ifunction ifunction_t; + typedef vector_holder vector_t; #ifndef exprtk_disable_string_capabilities typedef typename details::stringvar_node stringvar_node_t; #endif @@ -6873,6 +7112,71 @@ namespace exprtk } } + template + inline bool add_impl(const std::string& symbol_name, RType t, const bool is_constant) + { + if (1 == symbol_name.size()) + { + short_type_lut[static_cast(std::tolower(symbol_name[0]))] = Tie::make(t,is_constant); + ++size; + } + else + { + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + if (details::imatch(symbol_name,details::reserved_symbols[i])) + { + return false; + } + } + tm_itr_t itr = map.find(symbol_name); + if (map.end() == itr) + { + map[symbol_name] = Tie::make(t,is_constant); + ++size; + } + } + return true; + } + + inline bool add(const std::string& symbol_name, T* v, const std::size_t& v_size, const bool is_constant = false) + { + struct tie + { + static inline std::pair make(std::pair v, const bool is_constant = false) + { + return std::make_pair(is_constant,new vector_t(v.first,v.second)); + } + }; + return add_impl >(symbol_name,std::make_pair(v,v_size),is_constant); + } + + template + inline bool add(const std::string& symbol_name, std::vector& v, const bool is_constant = false) + { + struct tie + { + static inline std::pair make(std::vector& v, const bool is_constant = false) + { + return std::make_pair(is_constant,new vector_t(v)); + } + }; + return add_impl&>(symbol_name,v,is_constant); + } + + template + inline bool add(const std::string& symbol_name, std::deque& v, const bool is_constant = false) + { + struct tie + { + static inline std::pair make(std::deque& v, const bool is_constant = false) + { + return std::make_pair(is_constant,new vector_t(v)); + } + }; + return add_impl&>(symbol_name,v,is_constant); + } + inline bool add(const std::string& symbol_name, RawType& t, const bool is_constant = false) { struct tie @@ -6968,6 +7272,7 @@ namespace exprtk struct deleter { static inline void process(std::pair& n) { delete n.second; } + static inline void process(std::pair& n) { delete n.second; } #ifndef exprtk_disable_string_capabilities static inline void process(std::pair& n) { delete n.second; } #endif @@ -7112,6 +7417,7 @@ namespace exprtk #endif typedef ifunction function_t; typedef function_t* function_ptr; + typedef vector_holder* vector_ptr; static const std::size_t lut_size = 256; @@ -7125,6 +7431,7 @@ namespace exprtk type_store,std::string> stringvar_store; #endif type_store,ifunction > function_store; + type_store,vector_holder > vector_store; st_data() { @@ -7253,6 +7560,14 @@ namespace exprtk 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) { if (!valid()) @@ -7285,6 +7600,16 @@ namespace exprtk return local_data().function_store.get(function_name); } + inline vector_ptr get_vector(const std::string& vector_name) + { + 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); @@ -7414,6 +7739,44 @@ namespace exprtk return local_data().function_store.add(function_name,function); } + inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else + return local_data().vector_store.add(vector_name,v,v_size); + } + + template + 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 + return local_data().vector_store.add(vector_name,v); + } + + template + inline bool add_vector(const std::string& vector_name, std::deque& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + inline bool remove_variable(const std::string& variable_name) { if (!valid()) @@ -7440,6 +7803,14 @@ namespace exprtk return local_data().function_store.remove(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() && @@ -7507,6 +7878,16 @@ namespace exprtk } #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 { /* @@ -8353,6 +8734,7 @@ namespace exprtk 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"; @@ -8382,6 +8764,11 @@ namespace exprtk current_state.set(e_level03,e_level04,details::e_xor); break; } + else if (details::imatch(current_token_.value,s_xnor)) + { + current_state.set(e_level03,e_level04,details::e_xnor); + break; + } else if (details::imatch(current_token_.value,s_in)) { current_state.set(e_level03,e_level04,details::e_in); @@ -9285,6 +9672,7 @@ namespace exprtk 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"; } } @@ -9308,6 +9696,7 @@ namespace exprtk (details::e_or == operation) || (details::e_nor == operation) || (details::e_xor == operation) || + (details::e_xnor == operation) || false; } @@ -9976,6 +10365,7 @@ namespace exprtk 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