Back to index

texmacs  1.0.7.15
bridge_docrange.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : bridge_docrange.cpp
00004 * DESCRIPTION: Bridge between logical and physically typesetted document
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This file contains a VERY HACKY way to accelerate the editing of
00008 * document nodes with many (> 32) children. It should be noticed that
00009 * the notification call-back methods do not behave as usual: the st tree
00010 * remains the st tree of the entire document tree and brs stands for
00011 * a reference to the corresponding bridges. The bridge_docrange structure
00012 * only behaves as usual for the my_exec_until, my_typeset_will_be_complete
00013 * and my_typeset methods.
00014 *******************************************************************************
00015 * This software falls under the GNU general public license version 3 or later.
00016 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00017 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00018 ******************************************************************************/
00019 
00020 #include "bridge.hpp"
00021 
00022 #define ACC_THRESHOLD 32
00023 
00024 /******************************************************************************
00025 * The docrange bridge structure
00026 ******************************************************************************/
00027 
00028 class bridge_docrange_rep: public bridge_rep {
00029 protected:
00030   array<bridge> acc;
00031   array<bridge>& brs;
00032   array<int> mid;
00033   int begin, end;
00034   bool divide;
00035 
00036 public:
00037   bridge_docrange_rep (typesetter ttt, tree st, path ip, array<bridge>& brs,
00038                      int begin, int end, bool divide);
00039   void rebalance ();
00040 
00041   void notify_assign (path p, tree u);
00042   void notify_insert (path p, tree u);
00043   void notify_remove (path p, int nr);
00044   bool notify_macro  (int type, string var, int l, path p, tree u);
00045   void notify_change ();
00046 
00047   void my_exec_until (path p);
00048   bool my_typeset_will_be_complete ();
00049   void my_typeset (int desired_status);
00050 };
00051 
00052 bridge
00053 bridge_docrange (typesetter ttt, tree st, path ip,
00054                array<bridge>& brs, int begin, int end, bool divide= false)
00055 {
00056   // cout << "Make range: " << begin << " -- " << end << "\n";
00057   return tm_new<bridge_docrange_rep> (ttt, st, ip, brs, begin, end, divide);
00058 }
00059 
00060 bridge_docrange_rep::bridge_docrange_rep (
00061   typesetter ttt, tree st, path ip, array<bridge>& brs2,
00062   int begin2, int end2, bool divide2):
00063     bridge_rep (ttt, st, ip), brs (brs2),
00064     begin (begin2), end (end2), divide (divide2)
00065 {
00066   if (divide) {
00067     int i, n= ((end - begin - 1) / ACC_THRESHOLD) + 1;
00068     acc= array<bridge> (n);
00069     mid= array<int> (n+1);
00070     for (i=0; i<n; i++) {
00071       mid[i]  = begin + i * ACC_THRESHOLD;
00072       mid[i+1]= min (mid[i] + ACC_THRESHOLD, end);
00073       acc[i]  = bridge_docrange (ttt, st, ip, brs, mid[i], mid[i+1]);
00074     }
00075   }
00076 }
00077 
00078 void
00079 bridge_docrange_rep::rebalance () {
00080   int i, n= N(acc);
00081   array<bridge> acc2;
00082   array<int>    mid2;
00083 
00084   for (i=0; i<n; i++) {
00085     // Compactify?
00086     if ((i < n-1) && ((mid[i+2] == mid[i+1]) ||
00087                     (mid[i+2] - mid[i] <= ACC_THRESHOLD)))
00088       {
00089        int start= i;
00090        while ((i < n-1) && ((mid[i+2] == mid[start+1]) ||
00091                           (mid[i+2] - mid[start] <= ACC_THRESHOLD))) i++;
00092        // cout << "  Compactify " << i-start << " at " << start << ", ";
00093        // if (mid[i+1] == mid[start+1]) cout << "suppress\n";
00094        // else cout << "compress\n";
00095        if (mid[i+1] == mid[start+1]) acc2 << acc[start];
00096        else acc2 << bridge_docrange (ttt, st, ip, brs, mid[start], mid[i+1]);
00097        mid2 << mid[start];
00098       }
00099     
00100     // Expand?
00101     else if (mid[i+1] - mid[i] > (7 * ACC_THRESHOLD / 4)) {
00102       int j, k= (mid[i+1] - mid[i] - 1) / ACC_THRESHOLD + 1;
00103       // cout << "  Expand " << k << " at " << i << "\n";
00104       for (j=0; j<k; j++) {
00105        int b= mid[i] + j * ACC_THRESHOLD;
00106        int e= min (b + ACC_THRESHOLD, mid[i+1]);
00107        acc2 << bridge_docrange (ttt, st, ip, brs, b, e);
00108        mid2 << b;
00109       }
00110     }
00111     
00112     // OK
00113     else {
00114       acc2 << acc[i];
00115       mid2 << mid[i];
00116     }
00117   }
00118 
00119   mid2 << end;
00120   // if (mid2 != mid) cout << mid << " -> " << mid2 << "\n";
00121   acc= acc2;
00122   mid= mid2;
00123 }
00124 
00125 /******************************************************************************
00126 * Event notification
00127 ******************************************************************************/
00128 
00129 void
00130 bridge_docrange_rep::notify_assign (path p, tree u) {
00131   ASSERT (!is_nil (p), "erroneous nil path");
00132   if (divide) {
00133     int i, n= N(acc);
00134     for (i=0; i<n; i++)
00135       if ((p->item >= mid[i]) && (p->item < mid[i+1]))
00136        acc[i]->notify_assign (p, u);
00137   }
00138   status= CORRUPTED;
00139 }
00140 
00141 void
00142 bridge_docrange_rep::notify_insert (path p, tree u) {
00143   // cout << "Notify insert " << p << ", " << N(u)
00144   //      << " [ " << begin << "--" << end << " ]\n";
00145   ASSERT (!is_nil (p), "erroneous nil path");
00146   if (p->item > end) {
00147     cerr << "\nNotify insert " << u << " at " << p << "\n";
00148     FAILED ("out of range");
00149   }
00150   if (p->item >= begin) status= CORRUPTED;
00151   else begin += N(u);
00152   end += N(u);
00153 
00154   if (divide) {
00155     int i, n= N(acc);
00156     for (i=0; i<n; i++)
00157       if (p->item < mid[i+1])
00158        break;
00159     if (i==n) i--;
00160     for (; i<n; i++) {
00161       acc[i]->notify_insert (p, u);
00162       mid[i+1] += N(u);
00163     }
00164     // cout << "mid[ins,0]= " << mid << "\n";
00165     rebalance ();
00166     // cout << "mid[ins,1]= " << mid << "\n";
00167   }
00168 }
00169 
00170 void
00171 bridge_docrange_rep::notify_remove (path p, int nr) {
00172   // cout << "Notify insert " << p << ", " << nr
00173   //      << " [ " << begin << "--" << end << " ]\n";
00174   ASSERT (!is_nil (p), "erroneous nil path");
00175   ASSERT (p->item < end, "out of range");
00176   if (p->item + nr > begin) {
00177     status= CORRUPTED;
00178     begin= min (begin , p->item);
00179     end  = max (end-nr, p->item);
00180   }
00181   else {
00182     begin -= nr;
00183     end   -= nr;
00184   }
00185 
00186   if (divide) {
00187     int i, n= N(acc);
00188     for (i=0; i<n; i++)
00189       if (p->item < mid[i+1])
00190        break;
00191     for (; i<n; i++) {
00192       acc[i]->notify_remove (p, nr);
00193       mid[i+1]= max (mid[i+1]-nr, p->item);
00194     }
00195     // cout << "mid[rem,0]= " << mid << "\n";
00196     rebalance ();
00197     // cout << "mid[rem,1]= " << mid << "\n";
00198   }
00199 }
00200 
00201 bool
00202 bridge_docrange_rep::notify_macro (int type, string v, int l, path p, tree u) {
00203   (void) type; (void) v; (void) l; (void) p; (void) u;
00204   FAILED ("method should never be called");
00205   return false;
00206 }
00207 
00208 void
00209 bridge_docrange_rep::notify_change () {
00210   status= CORRUPTED;
00211   if (divide) {
00212     acc[0]->notify_change ();
00213     if (N(acc)>1) acc[N(acc)-1]->notify_change ();
00214   }
00215 }
00216 
00217 /******************************************************************************
00218 * Typesetting
00219 ******************************************************************************/
00220 
00221 void
00222 bridge_docrange_rep::my_exec_until (path p) {
00223   if (p->item < begin);
00224   else if ((p->item >= end) && ((status & VALID_MASK) == PROCESSED))
00225     env->patch_env (changes);
00226   else if (divide) {
00227     int i, n= N(acc);
00228     for (i=0; i<n; i++)
00229       acc[i]->my_exec_until (p);
00230   }
00231   else {
00232     int i;
00233     for (i=begin; i<p->item; i++)
00234       brs[i]->exec_until (path (right_index (brs[i]->st)), true);
00235     if (p->item < end) brs[i]->exec_until (p->next);
00236   }
00237 }
00238 
00239 bool
00240 bridge_docrange_rep::my_typeset_will_be_complete () {
00241   int i, n= N(acc);
00242   if (divide)
00243     for (i=0; i<n; i++)
00244       if (!acc[i]->my_typeset_will_be_complete ()) return false;
00245   else
00246     for (i=begin; i<end; i++)
00247       if (!brs[i]->my_typeset_will_be_complete ()) return false;
00248   return true;
00249 }
00250 
00251 // static bool top_level= true;
00252 
00253 void
00254 bridge_docrange_rep::my_typeset (int desired_status) {
00255   int i, n= N(acc);
00256   array<line_item> a= ttt->a;
00257   array<line_item> b= ttt->b;
00258   if (divide) {
00259     for (i=0; i<n; i++) {
00260       int wanted= (i==n-1? desired_status & WANTED_MASK: WANTED_PARAGRAPH);
00261       ttt->a= (i==0  ? a: array<line_item> ());
00262       ttt->b= (i==n-1? b: array<line_item> ());
00263       acc[i]->typeset (PROCESSED+ wanted);
00264     }
00265   }
00266   else {
00267     //bool show= top_level;
00268     //bool old_top_level= top_level;
00269     //top_level= false;
00270     //if (show) cout << "Typeset range: " << begin << " -- " << end << "\n  ";
00271     for (i=begin; i<end; i++) {
00272       int wanted= (i==end-1? desired_status & WANTED_MASK: WANTED_PARAGRAPH);
00273       ttt->a= (i==0    ? a: array<line_item> ());
00274       ttt->b= (i==end-1? b: array<line_item> ());
00275       //if (show) cout << (brs[i]->status == PROCESSED + wanted);
00276       //if (show) cout.flush ();
00277       brs[i]->typeset (PROCESSED+ wanted);
00278     }
00279     //if (show) cout << "\n";
00280     //top_level= old_top_level;
00281   }
00282 }