basix_doc 0.1
|
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