[PATCH] Update documentation on extending GiNaC
--- doc/examples/mystring.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++++ doc/tutorial/ginac.texi | 51 ++++++++++++++-------- 2 files changed, 136 insertions(+), 19 deletions(-) diff --git a/doc/examples/mystring.cpp b/doc/examples/mystring.cpp new file mode 100644 index 0000000..cf0d8a2 --- /dev/null +++ b/doc/examples/mystring.cpp @@ -0,0 +1,104 @@ +/** + * @file mystring.cpp Example of extending GiNaC: writing new classes + */ +#include <iostream> +#include <string> +#include <stdexcept> +using namespace std; + +#include <ginac/ginac.h> +using namespace GiNaC; + +class mystring : public basic +{ + GINAC_DECLARE_REGISTERED_CLASS(mystring, basic) + +public: + mystring(const string &s); + mystring(const char *s); + ex eval(int level) const; + +private: + string str; + +protected: + void do_print(const print_context &c, unsigned level = 0) const; + +}; + +GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(mystring, basic, + print_func<print_context>(&mystring::do_print)) + +// ctors +mystring::mystring() : inherited(&mystring::tinfo_static) { } +mystring::mystring(const string &s) : inherited(&mystring::tinfo_static), str(s) { } +mystring::mystring(const char *s) : inherited(&mystring::tinfo_static), str(s) { } + +// comparison +int mystring::compare_same_type(const basic &other) const +{ + const mystring &o = static_cast<const mystring &>(other); + int cmpval = str.compare(o.str); + if (cmpval == 0) + return 0; + else if (cmpval < 0) + return -1; + else + return 1; +} + +// archiving/unarchiving +mystring::mystring(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) +{ + n.find_string("string", str); +} + +void mystring::archive(archive_node &n) const +{ + inherited::archive(n); + n.add_string("string", str); +} + +ex mystring::unarchive(const archive_node &n, lst &sym_lst) +{ + return (new mystring(n, sym_lst))->setflag(status_flags::dynallocated); +} + +// printing +void mystring::do_print(const print_context &c, unsigned level) const +{ + // print_context::s is a reference to an ostream + c.s << '\"' << str << '\"'; +} + +/** + * evaluation: all strings automatically converted to lowercase with + * non-alphabetic characters stripped, and empty strings removed + */ +ex mystring::eval(int level) const +{ + string new_str; + for (size_t i=0; i<str.length(); i++) { + char c = str[i]; + if (c >= 'A' && c <= 'Z') + new_str += tolower(c); + else if (c >= 'a' && c <= 'z') + new_str += c; + } + + if (new_str.length() == 0) + return 0; + else + return mystring(new_str).hold(); +} + +int main(int argc, char** argv) +{ + ex e = mystring("Hello, world!"); + cout << is_a<mystring>(e) << endl; + cout << ex_to<basic>(e).class_name() << endl; + cout << e << endl; + ex another = pow(mystring("One string"), 2*sin(Pi-mystring("Another string"))); + cout << another << endl; + return 0; +} diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index 2560703..2650462 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -7733,9 +7733,8 @@ The RTTI in GiNaC is based on two mechanisms: @item The @code{basic} class declares a member variable @code{tinfo_key} which -holds an unsigned integer that identifies the object's class. These numbers -are defined in the @file{tinfos.h} header file for the built-in GiNaC -classes. They all start with @code{TINFO_}. +holds a variable of @code{tinfo_t} type (which is actually just +@code{const void*}) that identifies the object's class. @item By means of some clever tricks with static members, GiNaC maintains a list @@ -7772,17 +7771,6 @@ using namespace std; using namespace GiNaC; @end example -The first thing we have to do is to define a @code{tinfo_key} for our new -class. This can be any arbitrary unsigned number that is not already taken -by one of the existing classes but it's better to come up with something -that is unlikely to clash with keys that might be added in the future. The -numbers in @file{tinfos.h} are modeled somewhat after the class hierarchy -which is not a requirement but we are going to stick with this scheme: - -@example -const unsigned TINFO_mystring = 0x42420001U; -@end example - Now we can write down the class declaration. The class stores a C++ @code{string} and the user shall be able to construct a @code{mystring} object from a C or C++ string: @@ -7866,11 +7854,14 @@ which are the two constructors we declared. Let's proceed step-by-step. The default constructor looks like this: @example -mystring::mystring() : inherited(TINFO_mystring) @{@} +mystring::mystring() : inherited(&mystring::tinfo_static) @{@} @end example The golden rule is that in all constructors you have to set the -@code{tinfo_key} member to the @code{TINFO_*} value of your class. Otherwise +@code{tinfo_key} member to the @code{&your_class_name::tinfo_static} +@footnote{each GiNaC class has static member called tinfo_static. +This member is declared by the GINAC_DECLARE_REGISTERED_CLASS macros +and defined by the GINAC_IMPLEMENT_REGISTERED_CLASS macros}. Otherwise it will be set by the constructor of the superclass and all hell will break loose in the RTTI. For your convenience, the @code{basic} class provides a constructor that takes a @code{tinfo_key} value, which we are using here @@ -7960,8 +7951,8 @@ all relevant member variables. Now the only thing missing is our two new constructors: @example -mystring::mystring(const string &s) : inherited(TINFO_mystring), str(s) @{@} -mystring::mystring(const char *s) : inherited(TINFO_mystring), str(s) @{@} +mystring::mystring(const string &s) : inherited(&mystring::tinfo_static), str(s) @{@} +mystring::mystring(const char *s) : inherited(&mystring::tinfo_static), str(s) @{@} @end example No surprises here. We set the @code{str} member from the argument and @@ -8100,7 +8091,7 @@ public: ex mystring::eval(int level) const @{ string new_str; - for (int i=0; i<str.length(); i++) @{ + for (size_t i=0; i<str.length(); i++) @{ char c = str[i]; if (c >= 'A' && c <= 'Z') new_str += tolower(c); @@ -8198,6 +8189,28 @@ should become a need. That's it. May the source be with you! +@subsection Upgrading extension classes from older version of GiNaC + +If you got some extension classes for GiNaC 1.3.X some changes are +necessary in order to make your code work with GiNaC 1.4. + +@itemize @bullet +@item constructors which set @code{tinfo_key} such as + +@example +myclass::myclass() : inherited(TINFO_myclass) @{@} +@end example + +need to be rewritten as + +@example +myclass::myclass() : inherited(&myclass::tinfo_static) @{@} +@end example + +@item TINO_myclass is not necessary any more and can be removed. + +@end itemize + @node A comparison with other CAS, Advantages, Adding classes, Top @c node-name, next, previous, up -- 1.4.4.4 -- All science is either physics or stamp collecting.
participants (1)
-
Alexei Sheplyakov