From d3fc062d05930de2b30fe4e3d219435ad8fe770a Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Sun, 2 Oct 2016 20:23:18 +1100 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) https://www.partow.net/programming/exprtk/index.html --- Makefile | 1 + exprtk.hpp | 670 ++++++++++++++++++++++++++++++----- exprtk_simple_example_04.cpp | 2 +- exprtk_simple_example_09.cpp | 12 +- exprtk_simple_example_10.cpp | 2 +- readme.txt | 124 ++++++- 6 files changed, 713 insertions(+), 98 deletions(-) diff --git a/Makefile b/Makefile index 9a2042e..4a1a20f 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ BUILD_LIST+=exprtk_simple_example_14 BUILD_LIST+=exprtk_simple_example_15 BUILD_LIST+=exprtk_simple_example_16 BUILD_LIST+=exprtk_simple_example_17 +BUILD_LIST+=exprtk_simple_example_18 all: $(BUILD_LIST) diff --git a/exprtk.hpp b/exprtk.hpp index 4cce6f4..ac65825 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -16487,6 +16488,12 @@ namespace exprtk 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 @@ -32153,7 +32160,7 @@ namespace exprtk free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + 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]) @@ -32179,7 +32186,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[1]); - return synthesize_sos_expression_impl(opr,s0,s1); + 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]) @@ -32217,7 +32224,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[1]); - return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); + 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]) @@ -32233,7 +32240,7 @@ namespace exprtk 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); + 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]) @@ -32253,7 +32260,7 @@ namespace exprtk result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); else { - expression_node_ptr temp = synthesize_sos_expression_impl(opr,s0,s1); + expression_node_ptr temp = synthesize_sos_expression_impl(opr,s0,s1); Type v = temp->value(); details::free_node(*node_allocator_,temp); result = node_allocator_->allocate(v); @@ -32275,7 +32282,7 @@ namespace exprtk free_node(*node_allocator_,branch[0]); free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + 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]) @@ -32332,7 +32339,7 @@ namespace exprtk details::free_all_nodes(*node_allocator_,branch); - return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); + 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]) @@ -34525,107 +34532,114 @@ namespace exprtk return true; } - namespace helper + namespace rtl { - namespace details + namespace io { - template - inline void print_type(const std::string& fmt, - const T v, - exprtk::details::numeric::details::real_type_tag) + namespace details { - 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; - - static void process(const std::string& scalar_format, parameter_list_t parameters) + template + inline void print_type(const std::string& fmt, + const T v, + exprtk::details::numeric::details::real_type_tag) { - for (std::size_t i = 0; i < parameters.size(); ++i) + 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; + + static void process(const std::string& scalar_format, parameter_list_t parameters) { - generic_type& gt = parameters[i]; - - typename exprtk::details::numeric::details::number_type::type num_type; - - switch (gt.type) + for (std::size_t i = 0; i < parameters.size(); ++i) { - case generic_type::e_scalar : print_type(scalar_format,scalar_t(gt)(),num_type); - break; + generic_type& gt = parameters[i]; - case generic_type::e_vector : { - vector_t vector(gt); + typename exprtk::details::numeric::details::number_type::type num_type; - for (std::size_t x = 0; x < vector.size(); ++x) - { - print_type(scalar_format,vector[x],num_type); + switch (gt.type) + { + case generic_type::e_scalar : print_type(scalar_format,scalar_t(gt)(),num_type); + break; - if ((x + 1) < vector.size()) - printf(" "); + case generic_type::e_vector : { + vector_t vector(gt); + + for (std::size_t x = 0; x < vector.size(); ++x) + { + print_type(scalar_format,vector[x],num_type); + + if ((x + 1) < vector.size()) + printf(" "); + } } - } - break; + break; - case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str()); - break; + case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str()); + break; - default : continue; + default : continue; + } } } + }; + + } // 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 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) + template + struct println : public exprtk::igeneric_function { - exprtk::enable_zero_parameters(*this); - } + typedef typename igeneric_function::parameter_list_t parameter_list_t; - inline T operator()(parameter_list_t parameters) - { - details::print_impl::process(scalar_format_,parameters); - return T(0); - } + using exprtk::igeneric_function::operator(); - std::string scalar_format_; - }; + println(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } - template - struct println : public exprtk::igeneric_function - { - typedef typename igeneric_function::parameter_list_t parameter_list_t; + inline T operator()(parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + printf("\n"); + return T(0); + } - using exprtk::igeneric_function::operator(); + std::string scalar_format_; + }; - 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_; - }; + } // namespace exprtk::rtl::io } } @@ -34740,6 +34754,496 @@ namespace exprtk #endif }; +} // namespace exprtk + +#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(View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset) , amount * sizeof(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(View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset) , amount * sizeof(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; + } + + return true; + } + + bool eof() + { + 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) + { + 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; + } + } + + 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) + { + file_descriptor* fd = reinterpret_cast(0); + + std::memcpy(reinterpret_cast(&fd), + reinterpret_cast(&v), + sizeof(fd)); + 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; + std::string access; + + file_name = to_str(string_t(parameters[0])); + + 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); + + std::memcpy(reinterpret_cast(&t), + reinterpret_cast(&fd), + sizeof(fd)); + 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])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->write(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + amount = std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(buffer,amount) ? 1 : 0); + } + + case 2 : { + vector_t vec(parameters[1]); + amount = vec.size(); + return T(fd->write(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + 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])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + 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]); + amount = vec.size(); + return T(fd->read(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + 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) + { + if (!symtab.add_function("open" ,o)) + return false; + else if (!symtab.add_function("close" ,c)) + return false; + else if (!symtab.add_function("write" ,w)) + return false; + else if (!symtab.add_function("read" ,r)) + return false; + else if (!symtab.add_function("getline",g)) + return false; + else if (!symtab.add_function("eof" ,e)) + return false; + else + return true; + } + }; + + } // namespace exprtk::rtl::io::file + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +namespace exprtk +{ namespace information { static const char* library = "Mathematical Expression Toolkit"; diff --git a/exprtk_simple_example_04.cpp b/exprtk_simple_example_04.cpp index 71432c6..72f1ddf 100644 --- a/exprtk_simple_example_04.cpp +++ b/exprtk_simple_example_04.cpp @@ -34,7 +34,7 @@ void fibonacci() compositor .add( - function_t( + function_t( // define function: fibonacci(x) "fibonacci", " var w := 0; " " var y := 0; " diff --git a/exprtk_simple_example_09.cpp b/exprtk_simple_example_09.cpp index 58f495f..ef59202 100644 --- a/exprtk_simple_example_09.cpp +++ b/exprtk_simple_example_09.cpp @@ -42,7 +42,7 @@ void primes() //Mode 1 - if statement based compositor .add( - function_t( + function_t( // define function: is_prime_impl1(x,y) "is_prime_impl1", " if (y == 1,true, " " if (0 == (x % y),false, " @@ -51,7 +51,7 @@ void primes() compositor .add( - function_t( + function_t( // define function: is_prime1(x) "is_prime1", " if (frac(x) != 0, false, " " if (x <= 0, false, " @@ -61,7 +61,7 @@ void primes() //Mode 2 - switch statement based compositor .add( - function_t( + function_t( // define function: is_prime_impl2(x,y) "is_prime_impl2", " switch " " { " @@ -73,7 +73,7 @@ void primes() compositor .add( - function_t( + function_t( // define function: is_prime2(x) "is_prime2", " switch " " { " @@ -86,7 +86,7 @@ void primes() //Mode 3 - switch statement and while-loop based compositor .add( - function_t( + function_t( // define function: is_prime_impl3(x,y) "is_prime_impl3", " while (y > 0) " " { " @@ -101,7 +101,7 @@ void primes() compositor .add( - function_t( + function_t( // define function: is_prime3(x) "is_prime3", " switch " " { " diff --git a/exprtk_simple_example_10.cpp b/exprtk_simple_example_10.cpp index ee53994..48f2078 100644 --- a/exprtk_simple_example_10.cpp +++ b/exprtk_simple_example_10.cpp @@ -42,7 +42,7 @@ void newton_sqrt() compositor .add( - function_t( + function_t( // define function: newton_sqrt(x) "newton_sqrt", " switch " " { " diff --git a/readme.txt b/readme.txt index 6d02b8c..f1017ab 100644 --- a/readme.txt +++ b/readme.txt @@ -627,7 +627,7 @@ A vector can be indexed resulting in a scalar value. Operations between a vector and scalar will result in a vector with a size equal to that of the original vector, whereas operations between vectors will result in a vector of size equal to that of the smaller of the -two. +two. In both mentioned cases, the operations will occur element-wise. (3) String Type @@ -745,6 +745,25 @@ registration of the symbol_tables to the expression. expression.value(); // 123 + 1 +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) + + +The 'vector' type must consist of a contiguous array of scalars which +can be one of the following: + + 1. std::vector + 2. scalar_t(&v)[N] + 3. scalar_t* and array size + 4. exprtk::vector_view + + (2) Expression A structure that holds an abstract syntax tree or AST for a specified expression and is used to evaluate said expression. Evaluation of the @@ -1284,7 +1303,8 @@ with vectors: Note: When one of the above described operations is being performed between two vectors, the operation will only span the size of the smallest vector. The elements of the larger vector outside of the -range will not be included. +range will not be included. The operation itself will be processed +element-wise over values the smaller of the two ranges. The following simple example demonstrates the vector processing capabilities by computing the dot-product of the vectors v0 and v1 and @@ -1308,9 +1328,9 @@ the previously mentioned dot-product computation expression: } -Note: When the aggregate operations denoted above are used in -conjunction with a vector or vector expression, the return value is -not a vector but rather a single value. +Note: When the aggregate or reduction operations denoted above are +used in conjunction with a vector or vector expression, the return +value is not a vector but rather a single value. var x[3] := { 1, 2, 3 }; @@ -1321,6 +1341,80 @@ not a vector but rather a single value. max(x / 2) == (3 / 2) sum(x > 0 and x < 5) == x[] + +When utilizing external user defined vectors via the symbol table as +opposed to expression local defined vectors, the typical 'add_vector' +method from the symbol table will register the entirety of the vector +that is passed. The following example attempts to evaluate the sum of +elements of the external user defined vector within a typical yet +trivial expression: + + std::string reduce_program = " sum(2 * v + 1) "; + + std::vector v0 { T(1.1), T(2.2), ..... , T(99.99) }; + + symbol_table_t symbol_table; + symbol_table.add_vector("v",v); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(reduce_program,expression); + + T sum = expression.value(); + + +For the most part, this is a very common use-case. However there may +be situations where one may want to evaluate the same vector oriented +expression many times over, but using different vectors or sub ranges +of the same vector of the same size to that of the original upon every +evaluation. + +The usual solution is to either recompile the expression for the new +vector instance, or to copy the contents from the new vector to the +symbol table registered vector and then perform the evaluation. When +the vectors are large or the re-evaluation attempts are numerous, +these solutions can become rather time consuming and generally +inefficient. + + std::vector v1 { T(2.2), T(2.2), ..... , T(2.2) }; + std::vector v2 { T(3.3), T(3.3), ..... , T(3.3) }; + std::vector v3 { T(4.4), T(4.4), ..... , T(4.4) }; + + std::vector> vv { v1, v2, v3 }; + ... + T sum = T(0); + + for (auto& w : vv) + { + v = w; // update vector + sum += expression.value(); + } + + +A solution to the above 'efficiency' problem, is to use the +exprtk::vector_view object. The vector_view is instantiated with a +size and backing based upon a vector. Upon evaluations if the backing +needs to be 'updated' to either another vector or sub-range, the +vector_view instance can be efficiently rebased, and the expression +evaluated as normal. + + exprtk::vector_view vv = exprtk::make_vector_view(v, v.size()); + + symbol_table_t symbol_table; + symbol_table.add_vector("v",vv); + + ... + + T sum = T(0); + + for (auto& w : vv) + { + vv.rebase(new_vec.data()); // update vector + sum += expression.value(); + } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [15 - USER DEFINED FUNCTIONS] @@ -2745,14 +2839,23 @@ into account when using ExprTk: (x + y) / (x - y); } - (30) For performance considerations, one should assume the actions + (30) It is recommended when prototyping expressions that the ExprTk + REPL be utilised, as it supports all the features available in + the library, including complete error analysis, benchmarking + and dependency dumps etc which allows for rapid + coding/prototyping and debug cycles without the hassle of + having to recompile test programs with expressions that have + been hard-coded. It's also a good source of truth for how the + library's various features can be applied. + + (31) For performance considerations, one should assume the actions of expression, symbol table and parser instance instantiation and destruction, and the expression compilation process itself to be of high latency. Hence none of them should be part of any performance critical code paths, and should instead occur entirely either before or after such code paths. - (31) Before jumping in and using ExprTk, do take the time to peruse + (32) Before jumping in and using ExprTk, do take the time to peruse the documentation and all of the examples, both in the main and the extras distributions. Having an informed general view of what can and can't be done, and how something should be done @@ -2879,6 +2982,7 @@ the ExprTk header. The defines are as follows: (5) exprtk_disable_enhanced_features (6) exprtk_disable_string_capabilities (7) exprtk_disable_superscalar_unroll + (8) exprtk_disable_rtl_io_file (1) exprtk_enable_debugging @@ -2919,6 +3023,11 @@ targeting non-superscalar architectures, it may be recommended to build using this particular option if efficiency of evaluations is of concern. +(8) exprtk_disable_rtl_io_file +This define will disable the file I/O RTL package features. When +present, any attempts to register the file I/O package with a given +symbol table will fail causing a compilation error. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [23 - FILES] @@ -2947,6 +3056,7 @@ files: (19) exprtk_simple_example_15.cpp (20) exprtk_simple_example_16.cpp (21) exprtk_simple_example_17.cpp + (22) exprtk_simple_example_18.cpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~