Back to index

texmacs  1.0.7.15
ip_observer.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : ip_observer.cpp
00004 * DESCRIPTION: Persistently attach inverse paths to trees
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * An inverse path observer maintains the inverse path of the position
00008 * of the corresponding tree with respect to the global meta-tree.
00009 *******************************************************************************
00010 * This software falls under the GNU general public license version 3 or later.
00011 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00012 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00013 ******************************************************************************/
00014 
00015 #include "modification.hpp"
00016 
00017 #define DETACHED (-5)
00018 extern tree the_et;
00019 
00020 /******************************************************************************
00021 * Definition of the ip_observer_rep class
00022 ******************************************************************************/
00023 
00024 class ip_observer_rep: public observer_rep {
00025   path ip;
00026 public:
00027   ip_observer_rep (path ip2): ip (ip2) {}
00028   int get_type () { return OBSERVER_IP; }
00029   tm_ostream& print (tm_ostream& out) { return out << " " << ip; }
00030 
00031   void announce (tree& ref, modification mod);
00032   void done     (tree& ref, modification mod);
00033   void touched  (tree& ref, path p);
00034 
00035   void notify_assign      (tree& ref, tree t);
00036   void notify_insert      (tree& ref, int pos, int nr);
00037   void notify_remove      (tree& ref, int pos, int nr);
00038   void notify_split       (tree& ref, int pos, tree prev);
00039   void notify_var_split   (tree& ref, tree t1, tree t2);
00040   void notify_join        (tree& ref, int pos, tree next);
00041   void notify_var_join    (tree& ref, tree t, int offset);
00042   void notify_assign_node (tree& ref, tree_label op);
00043   void notify_insert_node (tree& ref, int pos);
00044   void notify_remove_node (tree& ref, int pos);
00045   void notify_detach      (tree& ref, tree closest, bool right);
00046 
00047   bool get_ip (path& ip);
00048   bool set_ip (path ip);
00049 };
00050 
00051 /******************************************************************************
00052 * Call back routines for announcements
00053 ******************************************************************************/
00054 
00055 bool
00056 has_parent (path ip) {
00057   return !is_nil (ip) && last_item (ip) != DETACHED;
00058 }
00059 
00060 void
00061 ip_observer_rep::announce (tree& ref, modification mod) {
00062   (void) ref;
00063   //cout << "Announce " << ip << ", " << p << "\n";
00064   if (!has_parent (ip)) return;
00065   tree& parent (subtree (the_et, reverse (ip->next)));
00066   parent->obs->announce (parent, ip->item * mod);
00067 }
00068 
00069 void
00070 ip_observer_rep::done (tree& ref, modification mod) {
00071   (void) ref;
00072   //cout << "Done " << ip << ", " << p << "\n";
00073   if (!has_parent (ip)) return;
00074   tree& parent (subtree (the_et, reverse (ip->next)));
00075   parent->obs->done (parent, ip->item * mod);
00076 }
00077 
00078 void
00079 ip_observer_rep::touched (tree& ref, path p) {
00080   (void) ref;
00081   //cout << "Touched " << ip << ", " << p << "\n";
00082   if (!has_parent (ip)) return;
00083   tree& parent (subtree (the_et, reverse (ip->next)));
00084   parent->obs->touched (parent, path (ip->item, p));
00085 }
00086 
00087 /******************************************************************************
00088 * Call back routines for modifications
00089 ******************************************************************************/
00090 
00091 void
00092 ip_observer_rep::notify_assign (tree& ref, tree t) {
00093   // cout << "Notify assign " << ref << ", " << t << "\n";
00094   path temp_ip= obtain_ip (ref);
00095   temp_ip= path (temp_ip->item, temp_ip->next); // prevents overriding temp_ip
00096   detach_ip (ref);
00097   attach_ip (t, temp_ip);
00098 }
00099 
00100 void
00101 ip_observer_rep::notify_insert (tree& ref, int pos, int nr) {
00102   // cout << "Notify insert " << ref << ", " << pos << ", " << nr << "\n";
00103   (void) nr;
00104   if (is_compound (ref)) {
00105     int i, n= N(ref);
00106     for (i=pos; i<n; i++)
00107       attach_ip (ref[i], path (i, ip));
00108   }
00109 }
00110 
00111 void
00112 ip_observer_rep::notify_remove (tree& ref, int pos, int nr) {
00113   // cout << "Notify remove " << ref << ", " << pos << ", " << nr << "\n";
00114   (void) nr;
00115   if (is_compound (ref)) {
00116     int i, n= N(ref);
00117     for (i=pos; i<(pos+nr); i++)
00118       detach_ip (ref[i]);
00119     for (; i<n; i++)
00120       attach_ip (ref[i], path (i-nr, ip));
00121   }
00122 }
00123 
00124 void
00125 ip_observer_rep::notify_split (tree& ref, int pos, tree prev) {
00126   // cout << "Notify split " << ref << ", " << pos << ", " << prev << "\n";
00127   int i, n= N(ref);
00128   detach_ip (prev);
00129   for (i=pos; i<n; i++)
00130     attach_ip (ref[i], path (i, ip));
00131 }
00132 
00133 void
00134 ip_observer_rep::notify_var_split (tree& ref, tree t1, tree t2) {
00135   (void) ref; (void) t1; (void) t2;
00136 }
00137 
00138 void
00139 ip_observer_rep::notify_join (tree& ref, int pos, tree next) {
00140   // cout << "Notify join " << ref << ", " << pos << ", " << next << "\n";
00141   int i, n= N(ref);
00142   detach_ip (ref[pos]);
00143   detach_ip (ref[pos+1]);
00144   for (i=pos+2; i<n; i++)
00145     attach_ip (ref[i], path (i-1, ip));
00146   attach_ip (next, path (pos, ip));
00147 }
00148 
00149 void
00150 ip_observer_rep::notify_var_join (tree& ref, tree t, int offset) {
00151   (void) ref; (void) t; (void) offset;
00152 }
00153 
00154 void
00155 ip_observer_rep::notify_assign_node (tree& ref, tree_label op) {
00156   // cout << "Notify assign node " << ref << ", " << as_string (op) << "\n";
00157   (void) ref; (void) op;
00158 }
00159 
00160 void
00161 ip_observer_rep::notify_insert_node (tree& ref, int pos) {
00162   // cout << "Notify insert node " << ref << ", " << pos << "\n";
00163   ip= path (pos, ip);
00164   attach_ip (ref[pos], ip); // updates children's ips
00165   attach_ip (ref, ip->next);
00166 }
00167 
00168 void
00169 ip_observer_rep::notify_remove_node (tree& ref, int pos) {
00170   // cout << "Notify remove node " << ref << ", " << pos << "\n";
00171   for (int i=0; i<N(ref); i++)
00172     if (i != pos)
00173       detach_ip (ref[i]);
00174   if ((!is_nil (ip)) && (ip->item>=0)) attach_ip (ref[pos], ip);
00175   else detach_ip (ref[pos]);
00176   ip= DETACHED; // detach_ip (ref);
00177 }
00178 
00179 void
00180 ip_observer_rep::notify_detach (tree& ref, tree closest, bool right) {
00181   (void) ref; (void) closest; (void) right;
00182 }
00183 
00184 /******************************************************************************
00185 * Setting and getting inverse paths
00186 ******************************************************************************/
00187 
00188 bool
00189 ip_observer_rep::get_ip (path& ip2) {
00190   ip2= ip;
00191   return true;
00192 }
00193 
00194 bool
00195 ip_observer_rep::set_ip (path ip2) {
00196   if (is_nil (ip) || is_nil (ip2))
00197     FAILED ("cannot alter global root");
00198   ip->item= ip2->item;
00199   ip->next= ip2->next;
00200   return true;
00201 }
00202 
00203 void
00204 attach_ip (tree& ref, path ip) {
00205   // cout << "Set ip of " << ref << " to " << ip << "\n";
00206   if (is_nil (ref->obs) || !ref->obs->set_ip (ip)) {
00207     // cout << "Create ip observer " << ip << " for " << ref << "\n";
00208     ref->obs= list_observer (ip_observer (ip), ref->obs);
00209   }
00210   if (is_compound (ref)) {
00211     int i, n= N(ref);
00212     for (i=0; i<n; i++) {
00213       path old_ip= obtain_ip (ref[i]);
00214       if ((old_ip->item != i) || (!strong_equal (old_ip->next, ip))) {
00215        attach_ip (ref[i], path (i, ip));
00216       }
00217     }
00218   }
00219 }
00220 
00221 void
00222 detach_ip (tree& ref) {
00223   // cout << "Detach ip of " << ref << "\n";
00224   if (!is_nil (ref->obs))
00225     (void) ref->obs->set_ip (DETACHED);
00226 }
00227 
00228 path
00229 obtain_ip (tree& ref) {
00230   path ip;
00231   if (is_nil (ref->obs)) return DETACHED;
00232   if (!ref->obs->get_ip (ip)) return DETACHED;
00233   return ip;
00234 }
00235 
00236 bool
00237 ip_attached (path ip) {
00238   return is_nil (ip) || last_item (ip) != DETACHED;
00239 }
00240 
00241 /******************************************************************************
00242 * Setting and getting inverse paths
00243 ******************************************************************************/
00244 
00245 observer
00246 ip_observer (path ip) {
00247   return tm_new<ip_observer_rep> (ip);
00248 }