GiNaC  1.6.2
class_info.h
Go to the documentation of this file.
00001 
00005 /*
00006  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022 
00023 #ifndef GINAC_CLASS_INFO_H
00024 #define GINAC_CLASS_INFO_H
00025 
00026 #include <cstddef> // for size_t
00027 #include <cstring>
00028 #include <iomanip>
00029 #include <iostream>
00030 #include <map>
00031 #include <stdexcept>
00032 #include <string>
00033 #include <vector>
00034 
00035 namespace GiNaC {
00036 
00037 // OPT is the class that stores the actual per-class data. It must provide
00038 // get_name(), get_parent_name() and get_id() members.
00039 
00040 template <class OPT>
00041 class class_info {
00042 public:
00043     class_info(const OPT & o) : options(o), next(first), parent(NULL)
00044     {
00045         first = this;
00046         parents_identified = false;
00047     }
00048 
00050     class_info *get_parent() const
00051     {
00052         identify_parents();
00053         return parent;
00054     }
00055 
00057     static const class_info *find(const std::string &class_name);
00058 
00060     static void dump_hierarchy(bool verbose = false);
00061 
00062     OPT options;
00063 
00064 private:
00065     struct tree_node {
00066         tree_node(class_info *i) : info(i) {}
00067         void add_child(tree_node *n) { children.push_back(n); }
00068 
00069         std::vector<tree_node *> children;
00070         class_info *info;
00071     };
00072 
00073     static void dump_tree(tree_node *n, const std::string & prefix, bool verbose);
00074     static void identify_parents();
00075 
00076     static class_info *first;
00077     class_info *next;
00078     mutable class_info *parent;
00079 
00080     static bool parents_identified;
00081 };
00082 
00083 template <class OPT>
00084 const class_info<OPT> *class_info<OPT>::find(const std::string &class_name)
00085 {
00086     // Use a map for faster lookup. The registered_class_info list doesn't
00087     // change at run-time, so it's sufficient to construct the map once
00088     // on the first trip through this function.
00089     typedef std::map<std::string, const class_info *> name_map_type;
00090     static name_map_type name_map;
00091     static bool name_map_initialized = false;
00092 
00093     if (!name_map_initialized) {
00094         // Construct map
00095         const class_info *p = first;
00096         while (p) {
00097             name_map[p->options.get_name()] = p;
00098             p = p->next;
00099         }
00100         name_map_initialized = true;
00101     }
00102 
00103     typename name_map_type::const_iterator it = name_map.find(class_name);
00104     if (it == name_map.end())
00105         throw (std::runtime_error("class '" + class_name + "' not registered"));
00106     else
00107         return it->second;
00108 }
00109 
00110 template <class OPT>
00111 void class_info<OPT>::dump_tree(tree_node *n, const std::string & prefix, bool verbose)
00112 {
00113     std::string name = n->info->options.get_name();
00114     std::cout << name;
00115     if (verbose)
00116         std::cout << " [ID 0x" << std::hex << std::setw(8) << std::setfill('0') << n->info->options.get_id() << std::dec << "]" << std::endl;
00117 
00118     size_t num_children = n->children.size();
00119     if (num_children) {
00120         for (size_t i = 0; i < num_children; ++i) {
00121             if (verbose) {
00122                 std::cout << prefix << " +- ";
00123                 if (i == num_children - 1)
00124                     dump_tree(n->children[i], prefix + "    ", verbose);
00125                 else
00126                     dump_tree(n->children[i], prefix + " |  ", verbose);
00127             } else {
00128                 std::string spaces(name.size(), ' ');
00129                 if (i > 0)
00130                     std::cout << prefix << spaces;
00131                 if (num_children == 1)
00132                     std::cout << " --- ";
00133                 else if (i > 0)
00134                     std::cout << "  +- ";
00135                 else
00136                     std::cout << " -+- ";
00137                 if (i == num_children - 1)
00138                     dump_tree(n->children[i], prefix + spaces + "     ", verbose);
00139                 else
00140                     dump_tree(n->children[i], prefix + spaces + "  |  ", verbose);
00141             }
00142         }
00143     } else if (!verbose)
00144         std::cout << std::endl;
00145 }
00146 
00147 template <class OPT>
00148 void class_info<OPT>::dump_hierarchy(bool verbose)
00149 {
00150     identify_parents();
00151 
00152     // Create tree nodes for all class_infos
00153     std::vector<tree_node> tree;
00154     for (class_info *p = first; p; p = p->next)
00155         tree.push_back(tree_node(p));
00156 
00157     // Identify children for all nodes and find the root
00158     tree_node *root = NULL;
00159     for (typename std::vector<tree_node>::iterator i = tree.begin(); i != tree.end(); ++i) {
00160         class_info *p = i->info->get_parent();
00161         if (p) {
00162             for (typename std::vector<tree_node>::iterator j = tree.begin(); j != tree.end(); ++j) {
00163                 if (j->info == p) {
00164                     j->add_child(&*i);
00165                     break;
00166                 }
00167             }
00168         } else
00169             root = &*i;
00170     }
00171 
00172     // Print hierarchy tree starting at the root
00173     dump_tree(root, "", verbose);
00174 }
00175 
00176 template <class OPT>
00177 void class_info<OPT>::identify_parents()
00178 {
00179     if (!parents_identified) {
00180         for (class_info *p = first; p; p = p->next) {
00181             const char *parent_name = p->options.get_parent_name();
00182             for (class_info *q = first; q; q = q->next) {
00183                 if (std::strcmp(q->options.get_name(), parent_name) == 0) {
00184                     p->parent = q;
00185                     break;
00186                 }
00187             }
00188         }
00189         parents_identified = true;
00190     }
00191 }
00192 
00193 template <class OPT> class_info<OPT> *class_info<OPT>::first = NULL;
00194 template <class OPT> bool class_info<OPT>::parents_identified = false;
00195 
00196 } // namespace GiNaC
00197 
00198 #endif // ndef GINAC_CLASS_INFO_H

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.