+#endif // ndef NO_NAMESPACE_GINAC
+
+function_options::function_options()
+{
+ initialize();
+}
+
+function_options::function_options(string const & n, string const & tn)
+{
+ initialize();
+ set_name(n,tn);
+}
+
+function_options::~function_options()
+{
+ // nothing to clean up at the moment
+}
+
+void function_options::initialize(void)
+{
+ set_name("unnamed_function","\\\\operatorname{unnamed}");
+ nparams=0;
+ eval_f=evalf_f=derivative_f=series_f=0;
+ evalf_params_first=true;
+ use_return_type=false;
+ use_remember=false;
+ functions_with_same_name=1;
+}
+
+function_options & function_options::set_name(string const & n,
+ string const & tn)
+{
+ name=n;
+ if (tn==string()) {
+ TeX_name="\\\\operatorname{"+name+"}";
+ } else {
+ TeX_name=tn;
+ }
+ return *this;
+}
+
+// the following lines have been generated for max. ${maxargs} parameters
+$eval_func_implementation
+$evalf_func_implementation
+$derivative_func_implementation
+$series_func_implementation
+// end of generated lines
+
+function_options & function_options::set_return_type(unsigned rt, unsigned rtt)
+{
+ use_return_type=true;
+ return_type=rt;
+ return_type_tinfo=rtt;
+ return *this;
+}
+
+function_options & function_options::do_not_evalf_params(void)
+{
+ evalf_params_first=false;
+ return *this;
+}
+
+function_options & function_options::remember(unsigned size,
+ unsigned assoc_size,
+ unsigned strategy)
+{
+ use_remember=true;
+ remember_size=size;
+ remember_assoc_size=assoc_size;
+ remember_strategy=strategy;
+ return *this;
+}
+
+function_options & function_options::overloaded(unsigned o)
+{
+ functions_with_same_name=o;
+ return *this;
+}
+
+void function_options::test_and_set_nparams(unsigned n)
+{
+ if (nparams==0) {
+ nparams=n;
+ } else if (nparams!=n) {
+ // we do not throw an exception here because this code is
+ // usually executed before main(), so the exception could not
+ // caught anyhow
+ cerr << "WARNING: number of parameters ("
+ << n << ") differs from number set before ("
+ << nparams << ")" << endl;
+ }
+}
+
+class remember_table_entry {
+public:
+ remember_table_entry(function const & f, ex const & r) :
+ hashvalue(f.gethash()), seq(f.seq), result(r)
+ {
+ last_access=0;
+ successful_hits=0;
+ }
+ bool is_equal(function const & f) const
+ {
+ GINAC_ASSERT(f.seq.size()==seq.size());
+ if (f.gethash()!=hashvalue) return false;
+ for (unsigned i=0; i<seq.size(); ++i) {
+ if (!seq[i].is_equal(f.seq[i])) return false;
+ }
+ last_access=access_counter++;
+ successful_hits++;
+ return true;
+ }
+ unsigned hashvalue;
+ exvector seq;
+ ex result;
+ mutable unsigned long last_access;
+ mutable unsigned successful_hits;
+
+ static unsigned access_counter;
+};
+
+unsigned remember_table_entry::access_counter=0;
+
+class remember_table_list : public list<remember_table_entry> {
+public:
+ remember_table_list()
+ {
+ max_assoc_size=0;
+ delete_strategy=0;
+ }
+ remember_table_list(unsigned as, unsigned strat)
+ {
+ max_assoc_size=as;
+ delete_strategy=strat;
+ }
+ void add_entry(function const & f, ex const & result)
+ {
+ push_back(remember_table_entry(f,result));
+ }
+ bool lookup_entry(function const & f, ex & result) const
+ {
+ for (const_iterator cit=begin(); cit!=end(); ++cit) {
+ if (cit->is_equal(f)) {
+ result=cit->result;
+ return true;
+ }
+ }
+ return false;
+ }
+protected:
+ unsigned max_assoc_size;
+ unsigned delete_strategy;
+};
+
+
+class remember_table : public vector<remember_table_list> {
+public:
+ remember_table()
+ {
+ }
+ remember_table(unsigned s, unsigned as, unsigned strat)
+ {
+ calc_size(s);
+ reserve(table_size);
+ for (unsigned i=0; i<table_size; ++i) {
+ push_back(remember_table_list(as,strat));
+ }
+ }
+ bool lookup_entry(function const & f, ex & result) const
+ {
+ unsigned entry=f.gethash() & (table_size-1);
+ if (entry>=size()) {
+ cerr << "entry=" << entry << ",size=" << size() << endl;
+ }
+ GINAC_ASSERT(entry<size());
+ return operator[](entry).lookup_entry(f,result);
+ }
+ void add_entry(function const & f, ex const & result)
+ {
+ unsigned entry=f.gethash() & (table_size-1);
+ GINAC_ASSERT(entry<size());
+ operator[](entry).add_entry(f,result);
+ }
+ void calc_size(unsigned s)
+ {
+ // use some power of 2 next to s
+ table_size=1 << log2(s);
+ }
+protected:
+ unsigned table_size;
+};
+
+// this is not declared as a static function in the class function
+// (like registered_function()) because of issues with cint
+static vector<remember_table> & remember_tables(void)
+{
+ static vector<remember_table> * rt=new vector<remember_table>;
+ return *rt;
+}
+
+GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)