#include "relational.h"
#include "operators.h"
#include "wildcard.h"
-#include "print.h"
#include "archive.h"
#include "utils.h"
namespace GiNaC {
-GINAC_IMPLEMENT_REGISTERED_CLASS(basic, void)
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(basic, void,
+ print_func<print_context>(&basic::do_print).
+ print_func<print_tree>(&basic::do_print_tree).
+ print_func<print_python_repr>(&basic::do_print_python_repr))
//////////
// default constructor, destructor, copy constructor and assignment operator
// public
-/** Output to stream.
+/** Output to stream. This performs double dispatch on the dynamic type of
+ * *this and the dynamic type of the supplied print context.
* @param c print context object that describes the output formatting
* @param level value that is used to identify the precedence or indentation
* level for placing parentheses and formatting */
void basic::print(const print_context & c, unsigned level) const
{
- if (is_a<print_tree>(c)) {
+ // Double dispatch on object type and print_context type
+ const registered_class_info * reg_info = &get_class_info();
+ const print_context_class_info * pc_info = &c.get_class_info();
- c.s << std::string(level, ' ') << class_name()
- << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
- << ", nops=" << nops()
- << std::endl;
- for (size_t i=0; i<nops(); ++i)
- op(i).print(c, level + static_cast<const print_tree &>(c).delta_indent);
+next_class:
+ const std::vector<print_functor> & pdt = reg_info->options.get_print_dispatch_table();
- } else
- c.s << "[" << class_name() << " object]";
+next_context:
+ unsigned id = pc_info->options.get_id();
+ if (id >= pdt.size() || !(pdt[id].is_valid())) {
+
+ // Method not found, try parent print_context class
+ const print_context_class_info * parent_pc_info = pc_info->get_parent();
+ if (parent_pc_info) {
+ pc_info = parent_pc_info;
+ goto next_context;
+ }
+
+ // Method still not found, try parent class
+ const registered_class_info * parent_reg_info = reg_info->get_parent();
+ if (parent_reg_info) {
+ reg_info = parent_reg_info;
+ pc_info = &c.get_class_info();
+ goto next_class;
+ }
+
+ // Method still not found. This shouldn't happen because basic (the
+ // base class of the algebraic hierarchy) registers a method for
+ // print_context (the base class of the print context hierarchy),
+ // so if we end up here, there's something wrong with the class
+ // registry.
+ throw (std::runtime_error(std::string("basic::print(): method for ") + class_name() + "/" + c.class_name() + " not found"));
+
+ } else {
+
+ // Call method
+ pdt[id](*this, c, level);
+ }
+}
+
+/** Default output to stream. */
+void basic::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "[" << class_name() << " object]";
+}
+
+/** Tree output to stream. */
+void basic::do_print_tree(const print_tree & c, unsigned level) const
+{
+ c.s << std::string(level, ' ') << class_name()
+ << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+ << ", nops=" << nops()
+ << std::endl;
+ for (size_t i=0; i<nops(); ++i)
+ op(i).print(c, level + c.delta_indent);
+}
+
+/** Python parsable output to stream. */
+void basic::do_print_python_repr(const print_python_repr & c, unsigned level) const
+{
+ c.s << class_name() << "()";
}
/** Little wrapper around print to be called within a debugger.
this->print(print_tree(std::cerr));
}
-/** Return relative operator precedence (for parenthizing output). */
+/** Return relative operator precedence (for parenthezing output). */
unsigned basic::precedence() const
{
return 70;
protected:
void ensure_if_modifiable() const;
+
+private:
+ void do_print(const print_context & c, unsigned level) const;
+ void do_print_tree(const print_tree & c, unsigned level) const;
+ void do_print_python_repr(const print_python_repr & c, unsigned level) const;
// member variables
protected:
{
// Optimal output of integer powers of symbols to aid compiler CSE.
// C.f. ISO/IEC 14882:1998, section 1.9 [intro execution], paragraph 15
- // to learn why such a parenthisation is really necessary.
+ // to learn why such a parenthesation is really necessary.
if (exp == 1) {
x.print(c);
} else if (exp == 2) {
#include <iosfwd>
#include <string>
+#include <memory>
#include "class_info.h"
public: \
typedef supername inherited; \
friend class function_options; \
+ friend class registered_class_options; \
private: \
static GiNaC::print_context_class_info reg_info; \
public: \
inline bool is_a(const print_context & obj)
{ return dynamic_cast<const T *>(&obj) != 0; }
+
+class basic;
+
+/** Base class for print_functor handlers */
+class print_functor_impl {
+public:
+ virtual ~print_functor_impl() {}
+ virtual print_functor_impl *duplicate() const = 0;
+ virtual void operator()(const basic & obj, const print_context & c, unsigned level) const = 0;
+};
+
+/** print_functor handler for pointer-to-functions of class T, context type C */
+template <class T, class C>
+class print_ptrfun_handler : public print_functor_impl {
+public:
+ typedef void (*F)(const T &, const C &, unsigned);
+
+ print_ptrfun_handler(F f_) : f(f_) {}
+ print_ptrfun_handler *duplicate() const { return new print_ptrfun_handler(*this); }
+
+ void operator()(const basic & obj, const print_context & c, unsigned level) const
+ {
+ // Call the supplied function
+ f(dynamic_cast<const T &>(obj), dynamic_cast<const C &>(c), level);
+ }
+
+private:
+ F f;
+};
+
+/** print_functor handler for member functions of class T, context type C */
+template <class T, class C>
+class print_memfun_handler : public print_functor_impl {
+public:
+ typedef void (T::*F)(const C & c, unsigned level);
+
+ print_memfun_handler(F f_) : f(f_) {}
+ print_memfun_handler *duplicate() const { return new print_memfun_handler(*this); }
+
+ void operator()(const basic & obj, const print_context & c, unsigned level) const
+ {
+ // Call the supplied member function
+ return (dynamic_cast<const T &>(obj).*f)(dynamic_cast<const C &>(c), level);
+ }
+
+private:
+ F f;
+};
+
+/** This class represents a print method for a certain algebraic class and
+ * print_context type. Its main purpose is to hide the difference between
+ * member functions and nonmember functions behind one unified operator()
+ * interface. print_functor has value semantics and acts as a smart pointer
+ * (with deep copy) to a class derived from print_functor_impl which
+ * implements the actual function call. */
+class print_functor {
+public:
+ print_functor() : impl(0) {}
+ print_functor(const print_functor & other) : impl(other.impl.get() ? other.impl->duplicate() : 0) {}
+ print_functor(std::auto_ptr<print_functor_impl> impl_) : impl(impl_) {}
+
+ template <class T, class C>
+ print_functor(void f(const T &, const C &, unsigned)) : impl(new print_ptrfun_handler<T, C>(f)) {}
+
+ template <class T, class C>
+ print_functor(void (T::*f)(const C &, unsigned)) : impl(new print_memfun_handler<T, C>(f)) {}
+
+ print_functor & operator=(const print_functor & other)
+ {
+ if (this != &other) {
+ print_functor_impl *p = other.impl.get();
+ impl.reset(p ? other.impl->duplicate() : 0);
+ }
+ return *this;
+ }
+
+ void operator()(const basic & obj, const print_context & c, unsigned level) const
+ {
+ (*impl)(obj, c, level);
+ }
+
+ bool is_valid() const { return impl.get(); }
+
+private:
+ std::auto_ptr<print_functor_impl> impl;
+};
+
+
} // namespace GiNaC
#endif // ndef __GINAC_BASIC_H__
#include <string>
#include <list>
+#include <vector>
#include "class_info.h"
+#include "print.h"
namespace GiNaC {
const char *get_parent_name() const { return parent_name; }
unsigned get_id() const { return tinfo_key; }
unarch_func get_unarch_func() const { return unarchive; }
+ const std::vector<print_functor> &get_print_dispatch_table() const { return print_dispatch_table; }
+
+ template <class Ctx, class T, class C>
+ registered_class_options & print_func(void f(const T &, const C & c, unsigned))
+ {
+ set_print_func(Ctx::reg_info.options.get_id(), f);
+ return *this;
+ }
+
+ template <class Ctx, class T, class C>
+ registered_class_options & print_func(void (T::*f)(const C &, unsigned))
+ {
+ set_print_func(Ctx::reg_info.options.get_id(), f);
+ return *this;
+ }
+
+ template <class Ctx>
+ registered_class_options & print_func(const print_functor & f)
+ {
+ set_print_func(Ctx::reg_info.options.get_id(), f);
+ return *this;
+ }
private:
+ void set_print_func(unsigned id, const print_functor & f)
+ {
+ if (id >= print_dispatch_table.size())
+ print_dispatch_table.resize(id + 1);
+ print_dispatch_table[id] = f;
+ }
+
const char *name; /**< Class name. */
const char *parent_name; /**< Name of superclass. */
unsigned tinfo_key; /**< TINFO_* key. */
unarch_func unarchive; /**< Pointer to unarchiving function. */
+ std::vector<print_functor> print_dispatch_table; /**< Method table for print() dispatch */
};
typedef class_info<registered_class_options> registered_class_info;