|
GiNaC
1.6.2
|
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