C++ Mathematical Expression Library (ExprTk) https://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
424b4628fa
commit
d3fc062d05
1
Makefile
1
Makefile
|
@ -41,6 +41,7 @@ BUILD_LIST+=exprtk_simple_example_14
|
||||||
BUILD_LIST+=exprtk_simple_example_15
|
BUILD_LIST+=exprtk_simple_example_15
|
||||||
BUILD_LIST+=exprtk_simple_example_16
|
BUILD_LIST+=exprtk_simple_example_16
|
||||||
BUILD_LIST+=exprtk_simple_example_17
|
BUILD_LIST+=exprtk_simple_example_17
|
||||||
|
BUILD_LIST+=exprtk_simple_example_18
|
||||||
|
|
||||||
|
|
||||||
all: $(BUILD_LIST)
|
all: $(BUILD_LIST)
|
||||||
|
|
508
exprtk.hpp
508
exprtk.hpp
|
@ -40,6 +40,7 @@
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -16487,6 +16488,12 @@ namespace exprtk
|
||||||
return add_constant("inf",local_infinity);
|
return add_constant("inf",local_infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Package>
|
||||||
|
inline bool add_package(Package& package)
|
||||||
|
{
|
||||||
|
return package.register_package(*this);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Allocator,
|
template <typename Allocator,
|
||||||
template <typename, typename> class Sequence>
|
template <typename, typename> class Sequence>
|
||||||
inline std::size_t get_variable_list(Sequence<std::pair<std::string,T>,Allocator>& vlist) const
|
inline std::size_t get_variable_list(Sequence<std::pair<std::string,T>,Allocator>& vlist) const
|
||||||
|
@ -34525,7 +34532,9 @@ namespace exprtk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace helper
|
namespace rtl
|
||||||
|
{
|
||||||
|
namespace io
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
|
@ -34580,7 +34589,8 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} // namespace exprtk::rtl::io::details
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct print : public exprtk::igeneric_function<T>
|
struct print : public exprtk::igeneric_function<T>
|
||||||
|
@ -34626,6 +34636,10 @@ namespace exprtk
|
||||||
|
|
||||||
std::string scalar_format_;
|
std::string scalar_format_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace exprtk::rtl::io
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34740,6 +34754,496 @@ namespace exprtk
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace exprtk
|
||||||
|
|
||||||
|
#ifndef exprtk_disable_rtl_io_file
|
||||||
|
#include <fstream>
|
||||||
|
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 <typename Stream, typename Ptr>
|
||||||
|
void close(Ptr& p)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(p);
|
||||||
|
stream->close();
|
||||||
|
delete stream;
|
||||||
|
p = reinterpret_cast<Ptr>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool close()
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case e_read : close<std::ifstream>(stream_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_write : close<std::ofstream>(stream_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_rdwrt : close<std::fstream> (stream_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default : return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename View>
|
||||||
|
bool write(const View& view, const std::size_t amount, const std::size_t offset = 0)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case e_write : reinterpret_cast<std::ofstream*>(stream_ptr)->
|
||||||
|
write(reinterpret_cast<const char*>(view.begin() + offset), amount * sizeof(View::value_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)->
|
||||||
|
write(reinterpret_cast<const char*>(view.begin() + offset) , amount * sizeof(View::value_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default : return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename View>
|
||||||
|
bool read(View& view, const std::size_t amount, const std::size_t offset = 0)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case e_read : reinterpret_cast<std::ifstream*>(stream_ptr)->
|
||||||
|
read(reinterpret_cast<char*>(view.begin() + offset), amount * sizeof(View::value_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)->
|
||||||
|
read(reinterpret_cast<char*>(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<std::ifstream*>(stream_ptr),s));
|
||||||
|
case e_rdwrt : return (!!std::getline(*reinterpret_cast<std::fstream* >(stream_ptr),s));
|
||||||
|
default : return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eof()
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case e_read : return reinterpret_cast<std::ifstream*>(stream_ptr)->eof();
|
||||||
|
case e_write : return reinterpret_cast<std::ofstream*>(stream_ptr)->eof();
|
||||||
|
case e_rdwrt : return reinterpret_cast<std::fstream* >(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 <typename T>
|
||||||
|
file_descriptor* make_handle(T v)
|
||||||
|
{
|
||||||
|
file_descriptor* fd = reinterpret_cast<file_descriptor*>(0);
|
||||||
|
|
||||||
|
std::memcpy(reinterpret_cast<char*>(&fd),
|
||||||
|
reinterpret_cast<const char*>(&v),
|
||||||
|
sizeof(fd));
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
class open : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename exprtk::igeneric_function<T> 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<T>::operator();
|
||||||
|
|
||||||
|
open()
|
||||||
|
: exprtk::igeneric_function<T>("S|SS")
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
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<char*>(&t),
|
||||||
|
reinterpret_cast<char*>(&fd),
|
||||||
|
sizeof(fd));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete fd;
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct close : public exprtk::ifunction<T>
|
||||||
|
{
|
||||||
|
using exprtk::ifunction<T>::operator();
|
||||||
|
|
||||||
|
close()
|
||||||
|
: exprtk::ifunction<T>(1)
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
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 <typename T>
|
||||||
|
class write : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename exprtk::igeneric_function<T> 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<T>::operator();
|
||||||
|
|
||||||
|
write()
|
||||||
|
: igfun_t("TS|TST|TV|TVT")
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
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<std::size_t>(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<std::size_t>(scalar_t(parameters[2])()));
|
||||||
|
return T(fd->write(vec,amount) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class read : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename exprtk::igeneric_function<T> 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<T>::operator();
|
||||||
|
|
||||||
|
read()
|
||||||
|
: igfun_t("TS|TST|TV|TVT")
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
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<std::size_t>(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<std::size_t>(scalar_t(parameters[2])()));
|
||||||
|
return T(fd->read(vec,amount) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class getline : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename exprtk::igeneric_function<T> 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<T>::operator();
|
||||||
|
|
||||||
|
getline()
|
||||||
|
: igfun_t("T",igfun_t::e_rtrn_string)
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
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 <typename T>
|
||||||
|
struct eof : public exprtk::ifunction<T>
|
||||||
|
{
|
||||||
|
using exprtk::ifunction<T>::operator();
|
||||||
|
|
||||||
|
eof()
|
||||||
|
: exprtk::ifunction<T>(1)
|
||||||
|
{ details::perform_check<T>(); }
|
||||||
|
|
||||||
|
inline T operator()(const T& v)
|
||||||
|
{
|
||||||
|
details::file_descriptor* fd = details::make_handle(v);
|
||||||
|
|
||||||
|
return (fd->eof() ? T(1) : T(0));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct package
|
||||||
|
{
|
||||||
|
open <T> o;
|
||||||
|
close <T> c;
|
||||||
|
write <T> w;
|
||||||
|
read <T> r;
|
||||||
|
getline<T> g;
|
||||||
|
eof <T> e;
|
||||||
|
|
||||||
|
bool register_package(exprtk::symbol_table<T>& 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
|
namespace information
|
||||||
{
|
{
|
||||||
static const char* library = "Mathematical Expression Toolkit";
|
static const char* library = "Mathematical Expression Toolkit";
|
||||||
|
|
|
@ -34,7 +34,7 @@ void fibonacci()
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: fibonacci(x)
|
||||||
"fibonacci",
|
"fibonacci",
|
||||||
" var w := 0; "
|
" var w := 0; "
|
||||||
" var y := 0; "
|
" var y := 0; "
|
||||||
|
|
|
@ -42,7 +42,7 @@ void primes()
|
||||||
//Mode 1 - if statement based
|
//Mode 1 - if statement based
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime_impl1(x,y)
|
||||||
"is_prime_impl1",
|
"is_prime_impl1",
|
||||||
" if (y == 1,true, "
|
" if (y == 1,true, "
|
||||||
" if (0 == (x % y),false, "
|
" if (0 == (x % y),false, "
|
||||||
|
@ -51,7 +51,7 @@ void primes()
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime1(x)
|
||||||
"is_prime1",
|
"is_prime1",
|
||||||
" if (frac(x) != 0, false, "
|
" if (frac(x) != 0, false, "
|
||||||
" if (x <= 0, false, "
|
" if (x <= 0, false, "
|
||||||
|
@ -61,7 +61,7 @@ void primes()
|
||||||
//Mode 2 - switch statement based
|
//Mode 2 - switch statement based
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime_impl2(x,y)
|
||||||
"is_prime_impl2",
|
"is_prime_impl2",
|
||||||
" switch "
|
" switch "
|
||||||
" { "
|
" { "
|
||||||
|
@ -73,7 +73,7 @@ void primes()
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime2(x)
|
||||||
"is_prime2",
|
"is_prime2",
|
||||||
" switch "
|
" switch "
|
||||||
" { "
|
" { "
|
||||||
|
@ -86,7 +86,7 @@ void primes()
|
||||||
//Mode 3 - switch statement and while-loop based
|
//Mode 3 - switch statement and while-loop based
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime_impl3(x,y)
|
||||||
"is_prime_impl3",
|
"is_prime_impl3",
|
||||||
" while (y > 0) "
|
" while (y > 0) "
|
||||||
" { "
|
" { "
|
||||||
|
@ -101,7 +101,7 @@ void primes()
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: is_prime3(x)
|
||||||
"is_prime3",
|
"is_prime3",
|
||||||
" switch "
|
" switch "
|
||||||
" { "
|
" { "
|
||||||
|
|
|
@ -42,7 +42,7 @@ void newton_sqrt()
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(
|
.add(
|
||||||
function_t(
|
function_t( // define function: newton_sqrt(x)
|
||||||
"newton_sqrt",
|
"newton_sqrt",
|
||||||
" switch "
|
" switch "
|
||||||
" { "
|
" { "
|
||||||
|
|
124
readme.txt
124
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
|
between a vector and scalar will result in a vector with a size equal
|
||||||
to that of the original vector, whereas operations between vectors
|
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
|
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
|
(3) String Type
|
||||||
|
@ -745,6 +745,25 @@ registration of the symbol_tables to the expression.
|
||||||
expression.value(); // 123 + 1
|
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<scalar_t>
|
||||||
|
2. scalar_t(&v)[N]
|
||||||
|
3. scalar_t* and array size
|
||||||
|
4. exprtk::vector_view<scalar_t>
|
||||||
|
|
||||||
|
|
||||||
(2) Expression
|
(2) Expression
|
||||||
A structure that holds an abstract syntax tree or AST for a specified
|
A structure that holds an abstract syntax tree or AST for a specified
|
||||||
expression and is used to evaluate said expression. Evaluation of the
|
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
|
Note: When one of the above described operations is being performed
|
||||||
between two vectors, the operation will only span the size of the
|
between two vectors, the operation will only span the size of the
|
||||||
smallest vector. The elements of the larger vector outside 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
|
The following simple example demonstrates the vector processing
|
||||||
capabilities by computing the dot-product of the vectors v0 and v1 and
|
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
|
Note: When the aggregate or reduction operations denoted above are
|
||||||
conjunction with a vector or vector expression, the return value is
|
used in conjunction with a vector or vector expression, the return
|
||||||
not a vector but rather a single value.
|
value is not a vector but rather a single value.
|
||||||
|
|
||||||
var x[3] := { 1, 2, 3 };
|
var x[3] := { 1, 2, 3 };
|
||||||
|
|
||||||
|
@ -1321,6 +1341,80 @@ not a vector but rather a single value.
|
||||||
max(x / 2) == (3 / 2)
|
max(x / 2) == (3 / 2)
|
||||||
sum(x > 0 and x < 5) == x[]
|
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<T> 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<T> v1 { T(2.2), T(2.2), ..... , T(2.2) };
|
||||||
|
std::vector<T> v2 { T(3.3), T(3.3), ..... , T(3.3) };
|
||||||
|
std::vector<T> v3 { T(4.4), T(4.4), ..... , T(4.4) };
|
||||||
|
|
||||||
|
std::vector<std::vector<T>> 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<T> 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]
|
[15 - USER DEFINED FUNCTIONS]
|
||||||
|
@ -2745,14 +2839,23 @@ into account when using ExprTk:
|
||||||
(x + y) / (x - y);
|
(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
|
of expression, symbol table and parser instance instantiation
|
||||||
and destruction, and the expression compilation process itself
|
and destruction, and the expression compilation process itself
|
||||||
to be of high latency. Hence none of them should be part of any
|
to be of high latency. Hence none of them should be part of any
|
||||||
performance critical code paths, and should instead occur
|
performance critical code paths, and should instead occur
|
||||||
entirely either before or after such code paths.
|
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 documentation and all of the examples, both in the main and
|
||||||
the extras distributions. Having an informed general view of
|
the extras distributions. Having an informed general view of
|
||||||
what can and can't be done, and how something should be done
|
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
|
(5) exprtk_disable_enhanced_features
|
||||||
(6) exprtk_disable_string_capabilities
|
(6) exprtk_disable_string_capabilities
|
||||||
(7) exprtk_disable_superscalar_unroll
|
(7) exprtk_disable_superscalar_unroll
|
||||||
|
(8) exprtk_disable_rtl_io_file
|
||||||
|
|
||||||
|
|
||||||
(1) exprtk_enable_debugging
|
(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
|
build using this particular option if efficiency of evaluations is of
|
||||||
concern.
|
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]
|
[23 - FILES]
|
||||||
|
@ -2947,6 +3056,7 @@ files:
|
||||||
(19) exprtk_simple_example_15.cpp
|
(19) exprtk_simple_example_15.cpp
|
||||||
(20) exprtk_simple_example_16.cpp
|
(20) exprtk_simple_example_16.cpp
|
||||||
(21) exprtk_simple_example_17.cpp
|
(21) exprtk_simple_example_17.cpp
|
||||||
|
(22) exprtk_simple_example_18.cpp
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue