manpagez: man pages & more
info ginac
Home | html | info | man
[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.3 GiNaC's expression output system

GiNaC allows the output of expressions in a variety of different formats (see section Input and output of expressions). This section will explain how expression output is implemented internally, and how to define your own output formats or change the output format of built-in algebraic objects. You will also want to read this section if you plan to write your own algebraic classes or functions.

All the different output formats are represented by a hierarchy of classes rooted in the print_context class, defined in the ‘print.h’ header file:

print_dflt

the default output format

print_latex

output in LaTeX mathematical mode

print_tree

a dump of the internal expression structure (for debugging)

print_csrc

the base class for C source output

print_csrc_float

C source output using the float type

print_csrc_double

C source output using the double type

print_csrc_cl_N

C source output using CLN types

The print_context base class provides two public data members:

 
class print_context
{
    ...
public:
    std::ostream & s;
    unsigned options;
};

s is a reference to the stream to output to, while options holds flags and modifiers. Currently, there is only one flag defined: print_options::print_index_dimensions instructs the idx class to print the index dimension which is normally hidden.

When you write something like std::cout << e, where e is an object of class ex, GiNaC will construct an appropriate print_context object (of a class depending on the selected output format), fill in the s and options members, and call

 
void ex::print(const print_context & c, unsigned level = 0) const;

which in turn forwards the call to the print() method of the top-level algebraic object contained in the expression.

Unlike other methods, GiNaC classes don't usually override their print() method to implement expression output. Instead, the default implementation basic::print(c, level) performs a run-time double dispatch to a function selected by the dynamic type of the object and the passed print_context. To this end, GiNaC maintains a separate method table for each class, similar to the virtual function table used for ordinary (single) virtual function dispatch.

The method table contains one slot for each possible print_context type, indexed by the (internally assigned) serial number of the type. Slots may be empty, in which case GiNaC will retry the method lookup with the print_context object's parent class, possibly repeating the process until it reaches the print_context base class. If there's still no method defined, the method table of the algebraic object's parent class is consulted, and so on, until a matching method is found (eventually it will reach the combination basic/print_context, which prints the object's class name enclosed in square brackets).

You can think of the print methods of all the different classes and output formats as being arranged in a two-dimensional matrix with one axis listing the algebraic classes and the other axis listing the print_context classes.

Subclasses of basic can, of course, also overload basic::print() to implement printing, but then they won't get any of the benefits of the double dispatch mechanism (such as the ability for derived classes to inherit only certain print methods from its parent, or the replacement of methods at run-time).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]
© manpagez.com 2000-2024
Individual documents may contain additional copyright information.