/** @file class_info.h
*
* Helper templates to provide per-class information for class hierarchies. */
/*
* GiNaC Copyright (C) 1999-2007 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __GINAC_CLASS_INFO_H__
#define __GINAC_CLASS_INFO_H__
#include <cstddef> // for size_t
#include <cstring>
#include <vector>
#include <map>
#include <string>
#include <iostream>
#include <iomanip>
#include <stdexcept>
namespace GiNaC {
// OPT is the class that stores the actual per-class data. It must provide
// get_name(), get_parent_name() and get_id() members.
template <class OPT>
class class_info {
public:
class_info(const OPT & o) : options(o), next(first), parent(NULL)
{
first = this;
parents_identified = false;
}
/** Get pointer to class_info of parent class (or NULL). */
class_info *get_parent() const
{
identify_parents();
return parent;
}
/** Find class_info by name. */
static const class_info *find(const std::string &class_name);
/** Dump class hierarchy to std::cout. */
static void dump_hierarchy(bool verbose = false);
OPT options;
private:
struct tree_node {
tree_node(class_info *i) : info(i) {}
void add_child(tree_node *n) { children.push_back(n); }
std::vector<tree_node *> children;
class_info *info;
};
static void dump_tree(tree_node *n, const std::string & prefix, bool verbose);
static void identify_parents();
static class_info *first;
class_info *next;
mutable class_info *parent;
static bool parents_identified;
};
template <class OPT>
const class_info<OPT> *class_info<OPT>::find(const std::string &class_name)
{
// Use a map for faster lookup. The registered_class_info list doesn't
// change at run-time, so it's sufficient to construct the map once
// on the first trip through this function.
typedef std::map<std::string, const class_info *> name_map_type;
static name_map_type name_map;
static bool name_map_initialized = false;
if (!name_map_initialized) {
// Construct map
const class_info *p = first;
while (p) {
name_map[p->options.get_name()] = p;
p = p->next;
}
name_map_initialized = true;
}
typename name_map_type::const_iterator it = name_map.find(class_name);
if (it == name_map.end())
throw (std::runtime_error("class '" + class_name + "' not registered"));
else
return it->second;
}
template <class OPT>
void class_info<OPT>::dump_tree(tree_node *n, const std::string & prefix, bool verbose)
{
std::string name = n->info->options.get_name();
std::cout << name;
if (verbose)
std::cout << " [ID 0x" << std::hex << std::setw(8) << std::setfill('0') << n->info->options.get_id() << std::dec << "]" << std::endl;
size_t num_children = n->children.size();
if (num_children) {
for (size_t i = 0; i < num_children; ++i) {
if (verbose) {
std::cout << prefix << " +- ";
if (i == num_children - 1)
dump_tree(n->children[i], prefix + " ", verbose);
else
dump_tree(n->children[i], prefix + " | ", verbose);
} else {
std::string spaces(name.size(), ' ');
if (i > 0)
std::cout << prefix << spaces;
if (num_children == 1)
std::cout << " --- ";
else if (i > 0)
std::cout << " +- ";
else
std::cout << " -+- ";
if (i == num_children - 1)
dump_tree(n->children[i], prefix + spaces + " ", verbose);
else
dump_tree(n->children[i], prefix + spaces + " | ", verbose);
}
}
} else if (!verbose)
std::cout << std::endl;
}
template <class OPT>
void class_info<OPT>::dump_hierarchy(bool verbose)
{
identify_parents();
// Create tree nodes for all class_infos
std::vector<tree_node> tree;
for (class_info *p = first; p; p = p->next)
tree.push_back(tree_node(p));
// Identify children for all nodes and find the root
tree_node *root = NULL;
for (typename std::vector<tree_node>::iterator i = tree.begin(); i != tree.end(); ++i) {
class_info *p = i->info->get_parent();
if (p) {
for (typename std::vector<tree_node>::iterator j = tree.begin(); j != tree.end(); ++j) {
if (j->info == p) {
j->add_child(&*i);
break;
}
}
} else
root = &*i;
}
// Print hierarchy tree starting at the root
dump_tree(root, "", verbose);
}
template <class OPT>
void class_info<OPT>::identify_parents()
{
if (!parents_identified) {
for (class_info *p = first; p; p = p->next) {
const char *parent_name = p->options.get_parent_name();
for (class_info *q = first; q; q = q->next) {
if (std::strcmp(q->options.get_name(), parent_name) == 0) {
p->parent = q;
break;
}
}
}
parents_identified = true;
}
}
template <class OPT> class_info<OPT> *class_info<OPT>::first = NULL;
template <class OPT> bool class_info<OPT>::parents_identified = false;
} // namespace GiNaC
#endif // ndef __GINAC_CLASS_INFO_H__
syntax highlighted by Code2HTML, v. 0.9.1