basix_doc 0.1
/Users/mourrain/Devel/mmx/basix/src/dynamic.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : dynamic.cpp
00004 * DESCRIPTION: Dynamic objects, capable of updating themselves automatically
00005 * COPYRIGHT  : (C) 2008  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #include <basix/dynamic.hpp>
00014 
00016 
00017 namespace mmx {
00018 
00019 /******************************************************************************
00020 * Dynamic objects
00021 ******************************************************************************/
00022 
00023 dynamic_rep::dynamic_rep (const generic& val2):
00024   val (val2) {}
00025 
00026 dynamic_rep::~dynamic_rep () {
00027   for (nat i=0; i<N(obs); i++)
00028     obs[i]->destroy ();
00029   obs= vector<observer> ();
00030 }
00031 
00032 void
00033 assign (const dynamic& d, const generic& val) {
00034   if (val == d->val) return;
00035   inside (d) -> val= val;
00036   for (nat i=0; i<N(d->obs); i++)
00037     d->obs[i]->modify ();
00038 }
00039 
00040 void
00041 message (const dynamic& d, const generic& msg) {
00042   for (nat i=0; i<N(d->obs); i++)
00043     d->obs[i]->message (msg);
00044 }
00045 
00046 void
00047 attach (const dynamic& d, const observer& o) {
00048   inside (d) -> obs << o;
00049 }
00050 
00051 void
00052 detach (const observer& o) {
00053   vector<observer>& obs= o->ref->obs;
00054   for (nat i=0; i<N(obs); i++)
00055     if (hard_eq (obs[i], o)) {
00056       obs= append (range (obs, 0, i), range (obs, i+1, N(obs)));
00057       return;
00058     }
00059   ERROR ("observer not attached");
00060 }
00061 
00062 /******************************************************************************
00063 * Output observers
00064 ******************************************************************************/
00065 
00066 void (*dynamic_event) (const string& id, const generic& val) = NULL;
00067 
00068 string
00069 unique_identifier (const dynamic& g) {
00070   return "mmx-" * as_string (hard_hash (g));
00071 }
00072 
00073 class output_observer_rep: public observer_rep {
00074 public:
00075   inline output_observer_rep (dynamic_rep* arg): observer_rep (arg) {}
00076   inline ~output_observer_rep () {}
00077   inline nat observer_type () const { return OUTPUT_OBSERVER; }
00078   inline void destroy () const {}
00079   inline void modify () const {
00080     if (dynamic_event == NULL) return;
00081     dynamic_event (unique_identifier (dynamic (ref, true)), ref->val); }
00082 };
00083 
00084 observer
00085 output_observer (dynamic_rep* arg) {
00086   return observer (new output_observer_rep (arg));
00087 }
00088 
00089 syntactic
00090 flatten (const dynamic& g) {
00091   syntactic r=
00092     apply ("$dynamic", syntactic (unique_identifier (g)), flatten (g->val));
00093   for (nat i=0; i<N(g->obs); i++)
00094     if (g->obs[i]->observer_type () == OUTPUT_OBSERVER)
00095       return r;
00096   attach (g, output_observer (inside (g)));
00097   inside (g) -> ref_count++;  // never destroy printed dynamic objects
00098   return r;
00099 }
00100 
00101 /******************************************************************************
00102 * Updaters
00103 ******************************************************************************/
00104 
00105 class updater;
00106 void destroy (const updater& u);  
00107 
00108 class updater_rep: public rep_struct {
00109 public:
00110   routine fun;
00111   dynamic_rep* ret;
00112   vector<dynamic> args;
00113   vector<observer> obs;
00114 
00115   inline updater_rep (const routine& fun2, dynamic_rep* ret2,
00116                       const vector<dynamic>& args2):
00117     fun (fun2), ret (ret2), args (args2) {}
00118   inline ~updater_rep () {}
00119   void update () const;
00120 
00121   friend class observer;
00122 };
00123 
00124 class updater {
00125 INDIRECT_PROTO (updater, updater_rep)
00126 public:
00127   inline updater (const routine& fun, dynamic_rep* ret,
00128                   const vector<dynamic>& args):
00129     rep (new updater_rep (fun, ret, args)) {}
00130   friend void destroy (const updater& u);
00131   friend class updater_rep;
00132 };
00133 INDIRECT_IMPL (updater, updater_rep)
00134 
00135 /******************************************************************************
00136 * Observers corresponding to updaters
00137 ******************************************************************************/
00138 
00139 class argument_observer_rep: public observer_rep {
00140 public:
00141   updater u;
00142 
00143   inline argument_observer_rep (dynamic_rep* arg, const updater& u2):
00144     observer_rep (arg), u (u2) {}
00145   inline ~argument_observer_rep () {}
00146   inline nat observer_type () const { return ARGUMENT_OBSERVER; }
00147   inline void destroy () const { mmx::destroy (u); }
00148   inline void modify () const { u->update (); }
00149 };
00150 
00151 observer
00152 argument_observer (dynamic_rep* arg, const updater& u) {
00153   return observer (new argument_observer_rep (arg, u));
00154 }
00155 
00156 class result_observer_rep: public observer_rep {
00157 public:
00158   updater u;
00159 
00160   inline result_observer_rep (dynamic_rep* res, const updater& u2):
00161     observer_rep (res), u (u2) {}
00162   inline ~result_observer_rep () {}
00163   inline nat observer_type () const { return RESULT_OBSERVER; }
00164   inline void destroy () const { mmx::destroy (u); }
00165   inline void modify () const {}
00166 };
00167 
00168 observer
00169 result_observer (dynamic_rep* arg, const updater& u) {
00170   return observer (new result_observer_rep (arg, u));
00171 }
00172 
00173 /******************************************************************************
00174 * Main routines for updaters
00175 ******************************************************************************/
00176 
00177 generic
00178 apply (const routine& fun, const vector<dynamic>& args) {
00179   vector<generic> a= fill<generic> (N (args));
00180   for (nat i= 0; i<N(a); i++)
00181     a[i]= args[i]->val;
00182   generic r= fun->apply (a);
00183   return r;
00184 }
00185 
00186 void
00187 updater_rep::update () const {
00188   vector<generic> a= fill<generic> (N (args));
00189   for (nat i= 0; i<N(a); i++) a[i]= args[i]->val;
00190   assign (dynamic (ret, true), fun->apply (a));
00191 }
00192 
00193 dynamic::dynamic (const routine& fun, const vector<dynamic>& args):
00194   rep (new dynamic_rep (apply (fun, args)))
00195 {
00196   updater u (fun, rep, args);
00197   for (nat i=0; i<N(args); i++) {
00198     observer arg_obs= argument_observer (inside (args[i]), u);
00199     attach (args[i], arg_obs);
00200     inside (u) -> obs << arg_obs;
00201   }
00202   observer res_obs= result_observer (rep, u);
00203   rep->obs << res_obs;
00204   inside (u) -> obs << res_obs;
00205 }
00206 
00207 void
00208 destroy (const updater& u) {
00209   for (nat i=0; i<N(u->obs); i++) detach (u->obs[i]);
00210   inside (u) -> args = vector<dynamic> ();
00211   inside (u) -> obs  = vector<observer> ();
00212 }
00213 
00214 } // namespace mmx
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines