Back to index

texmacs  1.0.7.15
link.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : hard_link.cpp
00004 * DESCRIPTION: Persistent hard_links between trees
00005 * COPYRIGHT  : (C) 2006  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "modification.hpp"
00013 #include "link.hpp"
00014 #include "iterator.hpp"
00015 #include "vars.hpp"
00016 
00017 hashmap<string,list<observer> > id_resolve;
00018 hashmap<observer,list<string> > pointer_resolve;
00019 hashmap<tree,list<soft_link> > vertex_occurrences;
00020 hashmap<string,int> type_count (0);
00021 
00022 static string current_locus_on_paper= "preserve";
00023 static string current_locus_color= "#404080";
00024 static string current_visited_color= "#702070";
00025 
00026 static hashset<string> visited_table;
00027 
00028 extern tree the_et;
00029 
00030 /******************************************************************************
00031 * Soft links
00032 ******************************************************************************/
00033 
00034 void
00035 register_pointer (string id, observer which) {
00036   // cout << "Register: " << id << " -> " << which << "\n";
00037   // cout << "Register: " << id << " -> " << obtain_tree (which) << "\n";
00038   list<observer>& l1= id_resolve (id);
00039   l1= list<observer> (which, l1);
00040   list<string>& l2= pointer_resolve (which);
00041   l2= list<string> (id, l2);
00042 }
00043 
00044 void
00045 unregister_pointer (string id, observer which) {
00046   // cout << "Unregister: " << id << " -> " << which << "\n";
00047   // cout << "Unregister: " << id << " -> " << obtain_tree (which) << "\n";
00048   list<observer>& l1= id_resolve (id);
00049   l1= remove (l1, which);
00050   if (is_nil (l1)) id_resolve->reset (id);
00051   list<string>& l2= pointer_resolve (which);
00052   l2= remove (l2, id);
00053   if (is_nil (l2)) pointer_resolve->reset (which);
00054 }
00055 
00056 void
00057 register_vertex (tree v, soft_link ln) {
00058   list<soft_link>& l= vertex_occurrences (v);
00059   l= list<soft_link> (ln, l);
00060 }
00061 
00062 void
00063 unregister_vertex (tree v, soft_link ln) {
00064   list<soft_link>& l= vertex_occurrences (v);
00065   l= remove (l, ln);
00066   if (is_nil (l)) vertex_occurrences->reset (v);
00067 }
00068 
00069 void
00070 register_link (soft_link ln) {
00071   // cout << "Register: " << ln->t << "\n";
00072   int i, n= N(ln->t);
00073   if (is_atomic (ln->t[0]))
00074     type_count (ln->t[0]->label) ++;
00075   for (i=1; i<n; i++)
00076     register_vertex (ln->t[i], ln);
00077 }
00078 
00079 void
00080 unregister_link (soft_link ln) {
00081   // cout << "Unregister: " << ln->t << "\n";
00082   int i, n= N(ln->t);
00083   if (is_atomic (ln->t[0])) {
00084     type_count (ln->t[0]->label) --;
00085     if (type_count (ln->t[0]->label) == 0)
00086       type_count->reset (ln->t[0]->label);
00087   }
00088   for (i=1; i<n; i++)
00089     unregister_vertex (ln->t[i], ln);
00090 }
00091 
00092 /******************************************************************************
00093 * Link repositories
00094 ******************************************************************************/
00095 
00096 link_repository_rep::link_repository_rep () {}
00097 
00098 link_repository_rep::~link_repository_rep () {
00099   while (!is_nil (loci)) {
00100     tree t= obtain_tree (loci->item);
00101     unregister_pointer (ids->item, loci->item);
00102     detach_observer (t, loci->item);
00103     ids= ids->next;
00104     loci= loci->next;
00105   }
00106   while (!is_nil (links)) {
00107     unregister_link (links->item);
00108     links= links->next;
00109   }
00110 }
00111 
00112 void
00113 link_repository_rep::insert_locus (string id, tree t) {
00114   observer obs= tree_pointer (t, true);
00115   register_pointer (id, obs);
00116   attach_observer (t, obs);
00117   ids= list<string> (id, ids);
00118   loci= list<observer> (obs, loci);
00119 }
00120 
00121 void
00122 link_repository_rep::insert_link (soft_link ln) {
00123   register_link (ln);
00124   links= list<soft_link> (ln, links);
00125 }
00126 
00127 /******************************************************************************
00128 * Routines for navigation
00129 ******************************************************************************/
00130 
00131 list<string>
00132 get_ids (list<observer> l) {
00133   if (is_nil (l)) return list<string> ();
00134   return pointer_resolve [l->item] * get_ids (l->next);
00135 }
00136 
00137 list<string>
00138 get_ids (tree t) {
00139   if (is_nil (t->obs)) return list<string> ();
00140   list<observer> l= t->obs->get_tree_pointers ();
00141   return reverse (get_ids (l));
00142 }
00143 
00144 list<tree>
00145 as_trees (list<observer> l) {
00146   if (is_nil (l)) return list<tree> ();
00147   else return list<tree> (obtain_tree (l->item), as_trees (l->next));
00148 }
00149 
00150 list<tree>
00151 get_trees (string id) {
00152   return reverse (as_trees (id_resolve [id]));
00153 }
00154 
00155 list<tree>
00156 as_tree_list (list<soft_link> l) {
00157   if (is_nil (l)) return list<tree> ();
00158   else return list<tree> (l->item->t, as_tree_list (l->next));
00159 }
00160 
00161 list<tree>
00162 get_links (tree v) {
00163   return reverse (as_tree_list (vertex_occurrences [v]));
00164 }
00165 
00166 list<string>
00167 all_link_types () {
00168   list<string> l;
00169   iterator<string> it= iterate (type_count);
00170   while (it->busy()) {
00171     string s= it->next();
00172     l= list<string> (s, l);
00173   }
00174   return l;
00175 }
00176 
00177 /******************************************************************************
00178 * Locus rendering
00179 ******************************************************************************/
00180 
00181 void
00182 set_locus_rendering (string var, string val) {
00183   if (var == "locus-on-paper") current_locus_on_paper= val;
00184   if (var == LOCUS_COLOR) current_locus_color= val;
00185   if (var == VISITED_COLOR) current_visited_color= val;
00186 }
00187 
00188 string
00189 get_locus_rendering (string var) {
00190   if (var == "locus-on-paper") return current_locus_on_paper;
00191   if (var == LOCUS_COLOR) return current_locus_color;
00192   if (var == VISITED_COLOR) return current_visited_color;
00193   return "";
00194 }
00195 
00196 void
00197 declare_visited (string id) {
00198   visited_table->insert (id);
00199 }
00200 
00201 bool
00202 has_been_visited (string id) {
00203   return visited_table->contains (id);
00204 }
00205 
00206 /******************************************************************************
00207 * Link event handlers for tree changes
00208 ******************************************************************************/
00209 
00210 tree&
00211 get_reference (tree& t) {
00212   path ip= obtain_ip (t);
00213   if (ip_attached (ip)) return subtree (the_et, reverse (ip));
00214   else return t;
00215 }
00216 
00217 list<tree>
00218 not_done (list<tree> l) {
00219   if (is_nil (l)) return l;
00220   else if (versioning_busy || busy_tree (get_reference (l->item)))
00221     return not_done (l->next);
00222   return list<tree> (l->item, not_done (l->next));
00223 }
00224 
00225 list<tree>
00226 get_mirrors (tree ln, string id) {
00227   if (!is_compound (ln, "link", 4) ||
00228       ln[0] != "mirror" ||
00229       !is_compound (ln[2], "id", 1) ||
00230       !is_atomic (ln[2][0]) ||
00231       !is_compound (ln[3], "id", 1) ||
00232       !is_atomic (ln[3][0]))
00233     return list<tree> ();
00234   if (ln[2][0] == id) return not_done (get_trees (ln[3][0]->label));
00235   if (ln[3][0] == id) return not_done (get_trees (ln[2][0]->label));
00236   return list<tree> ();
00237 }
00238 
00239 void
00240 link_announce (tree ln, string id, modification mod) {
00241   //cout << "Link event " << ln << ", " << id << ", " << mod << "\n";
00242   for (list<tree> l= get_mirrors (ln, id); !is_nil (l); l= l->next)
00243     if (is_applicable (l->item, mod))
00244       apply (get_reference (l->item), copy (mod));
00245 }
00246 
00247 void
00248 link_announce (observer obs, modification mod) {
00249   //cout << "Link event " << mod << "\n";
00250   for (list<string> ids= pointer_resolve [obs];
00251        !is_nil (ids); ids= ids->next)
00252     for (list<tree> lns= get_links (compound ("id", ids->item));
00253         !is_nil (lns); lns= lns->next)
00254       link_announce (lns->item, ids->item, mod);
00255 }