diff --git a/exprtk.hpp b/exprtk.hpp index 6b389de..9abf311 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -3950,9 +3950,12 @@ namespace exprtk { data_ = data; - if (data_ref_) + if (!data_ref_.empty()) { - (*data_ref_) = data; + for (std::size_t i = 0; i < data_ref_.size(); ++i) + { + (*data_ref_[i]) = data; + } } } @@ -3978,14 +3981,14 @@ namespace exprtk void set_ref(data_ptr_t* data_ref) { - data_ref_ = data_ref; + data_ref_.push_back(data_ref); } private: std::size_t size_; data_ptr_t data_; - data_ptr_t* data_ref_; + std::vector data_ref_; }; template @@ -4751,11 +4754,11 @@ namespace exprtk e_vovocov , e_vocovov , e_covovov , e_covocov , e_vocovoc , e_covovoc , e_vococov , e_sf3ext , e_sf4ext , e_nulleq , e_strass , e_vector , - e_vecelem , e_vecdefass , e_vecvalass , e_vecvecass , - e_vecopvalass , e_vecopvecass , e_vecfunc , e_vecvecswap , - e_vecvecineq , e_vecvalineq , e_valvecineq , e_vecvecarith , - e_vecvalarith , e_valvecarith , e_vecunaryop , e_break , - e_continue , e_swap + e_vecelem , e_rbvecelem , e_rbveccelem , e_vecdefass , + e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , + e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , + e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , + e_vecunaryop , e_break , e_continue , e_swap }; typedef T value_type; @@ -4845,8 +4848,10 @@ namespace exprtk { return node && ( - details::expression_node::e_variable == node->type() || - details::expression_node::e_vecelem == node->type() + 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() ); } @@ -4856,6 +4861,18 @@ namespace exprtk 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) { @@ -5071,6 +5088,11 @@ namespace exprtk return value_at(0); } + virtual inline bool rebaseable() const + { + return false; + } + virtual void set_ref(value_ptr*) {} protected: @@ -5157,6 +5179,11 @@ namespace exprtk vec_view_.set_ref(ref); } + virtual inline bool rebaseable() const + { + return true; + } + protected: value_ptr value_at(const std::size_t& index) const @@ -5217,6 +5244,11 @@ namespace exprtk return vector_holder_base_->set_ref(ref); } + bool rebaseable() const + { + return vector_holder_base_->rebaseable(); + } + private: mutable vector_holder_base* vector_holder_base_; @@ -6912,6 +6944,118 @@ namespace exprtk bool index_deletable_; }; + template + class rebasevector_elem_node : 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_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : index_(index), + index_deletable_(branch_deletable(index_)), + vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + ~rebasevector_elem_node() + { + if (index_ && index_deletable_) + { + delete index_; + } + } + + inline T value() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline T& ref() + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline const T& ref() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbvecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + expression_ptr index_; + bool index_deletable_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + + template + class rebasevector_celem_node : 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 + { + return *(vds_.data() + index_); + } + + inline T& ref() + { + return *(vds_.data() + index_); + } + + inline const T& ref() const + { + return *(vds_.data() + index_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbveccelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + std::size_t index_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + template class vector_assignment_node : public expression_node { @@ -9096,6 +9240,82 @@ namespace exprtk vector_elem_node* vec_node_ptr_; }; + template + class assignment_rebasevec_elem_node : 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 + { + if (rbvec_node_ptr_) + { + 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 : 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 + { + if (rbvec_node_ptr_) + { + 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 : public binary_node , public vector_interface @@ -9436,6 +9656,80 @@ namespace exprtk vector_elem_node* vec_node_ptr_; }; + template + class assignment_rebasevec_elem_op_node : 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 + { + if (rbvec_node_ptr_) + { + 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 : 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 + { + if (rbvec_node_ptr_) + { + 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 : public binary_node , public vector_interface @@ -10787,22 +11081,20 @@ namespace exprtk { public: - typedef type_store type_store_t; - typedef expression_node* expression_ptr; - typedef variable_node variable_node_t; - typedef vector_elem_node vector_elem_node_t; - typedef vector_node vector_node_t; - typedef variable_node_t* variable_node_ptr_t; - typedef vector_elem_node_t* vector_elem_node_ptr_t; - typedef vector_node_t* vector_node_ptr_t; - typedef range_interface range_interface_t; - typedef range_data_type range_data_type_t; - typedef range_pack 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; + 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 range_pack 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; generic_function_node(const std::vector& arg_list, GenericFunction* func = (GenericFunction*)(0)) @@ -16858,6 +17150,7 @@ namespace exprtk if (expr && details::branch_deletable(expr)) { delete expr; + expr = reinterpret_cast(0); } if (!local_data_list.empty()) @@ -17351,6 +17644,8 @@ namespace exprtk 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 @@ -17366,7 +17661,9 @@ namespace exprtk 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_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::scand_node scand_node_t; @@ -17435,10 +17732,11 @@ namespace exprtk }; typedef details::vector_holder vector_holder_t; - typedef variable_node_t* variable_node_ptr; - typedef vector_holder_t* vector_holder_ptr; + 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; + typedef stringvar_node_t* stringvar_node_ptr; #endif scope_element() @@ -17503,8 +17801,8 @@ namespace exprtk element_type type; bool active; void* data; - variable_node_ptr var_node; - vector_holder_ptr vec_node; + expression_node_ptr var_node; + vector_holder_ptr vec_node; #ifndef exprtk_disable_string_capabilities stringvar_node_ptr str_node; #endif @@ -17514,8 +17812,9 @@ namespace exprtk { public: - typedef variable_node_t* variable_node_ptr; - typedef parser parser_t; + typedef expression_node_t* expression_node_ptr; + typedef variable_node_t* variable_node_ptr; + typedef parser parser_t; scope_element_manager(parser& p) : parser_(p), @@ -17630,24 +17929,24 @@ namespace exprtk { switch (se.type) { - case scope_element::e_variable: if (se.data ) delete (T*) se.data; - if (se.var_node) delete se.var_node; - break; + case scope_element::e_variable : if (se.data ) delete (T*) se.data; + if (se.var_node) delete se.var_node; + break; - case scope_element::e_vector : if (se.data ) delete[] (T*) se.data; - if (se.vec_node) delete se.vec_node; - break; + case scope_element::e_vector : if (se.data ) delete[] (T*) se.data; + if (se.vec_node) delete se.vec_node; + break; - case scope_element::e_vecelem : if (se.var_node) delete se.var_node; - break; + case scope_element::e_vecelem : if (se.var_node) delete se.var_node; + break; #ifndef exprtk_disable_string_capabilities - case scope_element::e_string : if (se.data ) delete (std::string*) se.data; - if (se.str_node) delete se.str_node; - break; + case scope_element::e_string : if (se.data ) delete (std::string*) se.data; + if (se.str_node) delete se.str_node; + break; #endif - default : return; + default : return; } se.clear(); @@ -17670,22 +17969,28 @@ namespace exprtk return ++input_param_cnt_; } - inline variable_node_ptr get_variable(const T& v) + 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) + if ( + se.active && + se.var_node && + details::is_variable_node(se.var_node) + ) { - if (&se.var_node->ref() == (&v)) + variable_node_ptr vn = reinterpret_cast(se.var_node); + + if (&(vn->ref()) == (&v)) { return se.var_node; } } } - return variable_node_ptr(0); + return expression_node_ptr(0); } private: @@ -23179,7 +23484,7 @@ namespace exprtk return parse_define_string_statement(var_name,initialisation_expression); } - variable_node_t* var_node = reinterpret_cast(0); + expression_node_ptr var_node = reinterpret_cast(0); scope_element& se = sem_.get_element(var_name); @@ -23271,7 +23576,7 @@ namespace exprtk return error_node(); } - variable_node_t* var_node = reinterpret_cast(0); + expression_node_ptr var_node = reinterpret_cast(0); scope_element& se = sem_.get_element(var_name); @@ -24772,9 +25077,11 @@ namespace exprtk return !b1_is_genstring; else return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node(branch[0]) && - !details::is_vector_node (branch[0]) + !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; } @@ -26119,7 +26426,10 @@ namespace exprtk details::free_node(*node_allocator_,index); - Type* v = (*vector_base)[i]; + if (vector_base->rebaseable()) + { + return node_allocator_->allocate(i,vector_base); + } scope_element& se = parser_->sem_.get_element(symbol,i); @@ -26137,7 +26447,7 @@ namespace exprtk nse.index = i; nse.depth = parser_->state_.scope_depth; nse.data = 0; - nse.var_node = new variable_node_t((*v)); + nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); if (!parser_->sem_.add_element(nse)) { @@ -26155,8 +26465,10 @@ namespace exprtk result = nse.var_node; } } + else if (vector_base->rebaseable()) + result = node_allocator_->allocate(index,vector_base); else - result = node_allocator_->allocate >(index,vector_base); + result = node_allocator_->allocate(index,vector_base); return result; } @@ -26257,6 +26569,18 @@ namespace exprtk 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])) { @@ -26329,6 +26653,42 @@ namespace exprtk default : return error_node(); } } + else if (details::is_rebasevector_elem_node(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])) + { + 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]); diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 3f30047..9792186 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -6273,6 +6273,69 @@ inline bool run_test18() return false; } + { + bool failure = false; + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::vector v0; + std::vector s; + + #define pb(v,N) \ + v.push_back(T(N)); \ + + pb(v0,0) pb(v0,1) pb(v0,2) pb(v0,3) pb(v0,4) + pb(v0,5) pb(v0,6) pb(v0,7) pb(v0,8) pb(v0,9) + + pb(s, 3) pb(s, 6) pb(s, 9) pb(s,12) + pb(s,15) pb(s,18) pb(s,21) + #undef pb + + const std::string expr_string = "v[0] + v[1] + v[2]"; + + exprtk::vector_view v = exprtk::make_vector_view(v0,4); + + symbol_table_t symbol_table; + symbol_table.add_vector("v",v); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + + if (!parser.compile(expr_string,expression)) + { + printf("run_test18() - Error: %s\tExpression: %s\n", + parser.error().c_str(), + expr_string.c_str()); + + failure = true; + } + + for (std::size_t i = 0; i < v0.size() - 4; ++i) + { + v.rebase(v0.data() + i); + + T sum = expression.value(); + + if (not_equal(sum,s[i])) + { + printf("run_test18() - Error in evaluation! (7) Expression: %s Expected: %5.3f Computed: %5.3f\n", + expr_string.c_str(), + s[i], + sum); + + failure = true; + } + + } + + if (failure) + return false; + } + return true; } diff --git a/readme.txt b/readme.txt index 6133c44..eb17d2d 100644 --- a/readme.txt +++ b/readme.txt @@ -749,10 +749,10 @@ The symbol table supports adding references to external instances of types that can be accessed within expressions via the following methods: - 1. bool add_variable (const std::string& name, scalar_t) - 2. bool add_constant (const std::string& name,const scalar_t) - 3. bool add_stringvar(const std::string& name, std::string) - 4. bool add_vector (const std::string& name, vector_type) + 1. bool add_variable (const std::string& name, scalar_t&) + 2. bool add_constant (const std::string& name, const scalar_t&) + 3. bool add_stringvar(const std::string& name, std::string&) + 4. bool add_vector (const std::string& name, vector_type&) The 'vector' type must consist of a contiguous array of scalars which