Libbarrett
1.2.4
|
00001 /* 00002 Copyright 2009, 2010 Barrett Technology <support@barrett.com> 00003 00004 This file is part of libbarrett. 00005 00006 This version of libbarrett is free software: you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License as 00008 published by the Free Software Foundation, either version 3 of the 00009 License, or (at your option) any later version. 00010 00011 This version of libbarrett is distributed in the hope that it will be 00012 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License along 00017 with this version of libbarrett. If not, see 00018 <http://www.gnu.org/licenses/>. 00019 00020 Further, non-binding information about licensing is available at: 00021 <http://wiki.barrett.com/libbarrett/wiki/LicenseNotes> 00022 */ 00023 00032 #ifndef BARRETT_SYSTEMS_ABSTRACT_SYSTEM_H_ 00033 #define BARRETT_SYSTEMS_ABSTRACT_SYSTEM_H_ 00034 00035 00036 #include <string> 00037 #include <cassert> 00038 00039 #include <boost/intrusive/list.hpp> 00040 #include <boost/intrusive/parent_from_member.hpp> 00041 00042 #include <barrett/detail/ca_macro.h> 00043 #include <barrett/thread/abstract/mutex.h> 00044 00045 00046 namespace barrett { 00047 namespace systems { 00048 00049 00050 class ExecutionManager; 00051 00052 00053 #define DECLARE_HELPER_FRIENDS \ 00054 template<typename T2> friend void connect(System::Output<T2>& output, System::Input<T2>& input); \ 00055 template<typename T2> friend void disconnect(System::Input<T2>& input); \ 00056 template<typename T2> friend void disconnect(System::Output<T2>& output) 00057 00058 00059 class System { 00060 private: 00061 typedef uint_fast32_t update_token_type; 00062 00063 public: 00064 // Forward decls 00065 class AbstractInput; 00066 template<typename T> class Input; 00067 class AbstractOutput; 00068 template<typename T> class Output; 00069 00070 00071 explicit System(const std::string& sysName = "System") : 00072 name(sysName), em(NULL), emDirect(false), ut(UT_NULL) {} 00073 virtual ~System() { mandatoryCleanUp(); } 00074 00075 void setName(const std::string& newName) { name = newName; } 00076 const std::string& getName() const { return name; } 00077 00078 bool hasExecutionManager() const { return getExecutionManager() != NULL; } 00079 bool hasDirectExecutionManager() const { return emDirect; } 00080 ExecutionManager* getExecutionManager() const { return em; } 00081 thread::Mutex& getEmMutex() const; 00082 00083 protected: 00084 void mandatoryCleanUp(); 00085 00086 void update(update_token_type updateToken); 00087 00088 virtual bool inputsValid() /* const */; 00089 virtual void operate() = 0; 00090 virtual void invalidateOutputs(); 00091 00092 // If you redefine this method, make sure to call 00093 // MyBaseClass::onExecutionManagerChanged() in the new version. 00094 virtual void onExecutionManagerChanged() {} 00095 00096 std::string name; 00097 ExecutionManager* em; 00098 bool emDirect; 00099 00100 00101 public: 00102 class AbstractInput { 00103 public: 00104 AbstractInput(System* parent); 00105 virtual ~AbstractInput(); 00106 00107 virtual bool valueDefined() const = 0; 00108 00109 thread::Mutex& getEmMutex() const; 00110 00111 protected: 00112 virtual void mandatoryCleanUp(); 00113 00114 System* parentSys; 00115 00116 private: 00117 virtual void pushExecutionManager() = 0; 00118 virtual void unsetExecutionManager() = 0; 00119 00120 typedef boost::intrusive::list_member_hook<> child_hook_type; 00121 child_hook_type childHook; 00122 00123 friend class System; 00124 00125 DISALLOW_COPY_AND_ASSIGN(AbstractInput); 00126 }; 00127 00128 class AbstractOutput { 00129 public: 00130 AbstractOutput(System* parent); 00131 virtual ~AbstractOutput(); 00132 00133 thread::Mutex& getEmMutex() const; 00134 00135 protected: 00136 virtual void mandatoryCleanUp(); 00137 00138 System* parentSys; 00139 00140 private: 00141 virtual void setValueUndefined() = 0; 00142 00143 virtual ExecutionManager* collectExecutionManager() const = 0; 00144 virtual void pushExecutionManager() = 0; 00145 virtual void unsetExecutionManager() = 0; 00146 00147 typedef boost::intrusive::list_member_hook<> child_hook_type; 00148 child_hook_type childHook; 00149 00150 friend class System; 00151 00152 DISALLOW_COPY_AND_ASSIGN(AbstractOutput); 00153 }; 00154 00155 00156 private: 00157 static const update_token_type UT_NULL = 0; 00158 update_token_type ut; 00159 00160 00161 void setExecutionManager(ExecutionManager* newEm); 00162 void unsetDirectExecutionManager(); 00163 void unsetExecutionManager(); 00164 00165 typedef boost::intrusive::list_member_hook<> managed_hook_type; 00166 managed_hook_type managedHook; 00167 00168 struct StopManagingDisposer { 00169 void operator() (System* sys) { 00170 sys->unsetDirectExecutionManager(); 00171 } 00172 }; 00173 00174 typedef boost::intrusive::list<AbstractInput, boost::intrusive::member_hook<AbstractInput, AbstractInput::child_hook_type, &AbstractInput::childHook> > child_input_list_type; 00175 child_input_list_type inputs; 00176 00177 typedef boost::intrusive::list<AbstractOutput, boost::intrusive::member_hook<AbstractOutput, AbstractOutput::child_hook_type, &AbstractOutput::childHook> > child_output_list_type; 00178 child_output_list_type outputs; 00179 00180 00181 friend class ExecutionManager; 00182 DECLARE_HELPER_FRIENDS; 00183 00184 00185 DISALLOW_COPY_AND_ASSIGN(System); 00186 }; 00187 00188 00189 template<typename T> class System::Input : public System::AbstractInput { 00190 public: 00191 Input(System* parent) : AbstractInput(parent), output(NULL) {} 00192 virtual ~Input(); 00193 00194 bool isConnected() const { return output != NULL; } 00195 virtual bool valueDefined() const { 00196 assert(parentSys != NULL); 00197 return parentSys->hasExecutionManager() && isConnected() && output->getValueObject()->updateData(parentSys->ut); 00198 } 00199 00200 const T& getValue() const { 00201 assert(valueDefined()); 00202 00203 // valueDefined() calls Output<T>::Value::updateData() for us. Make 00204 // sure it gets called even if NDEBUG is defined. 00205 #ifdef NDEBUG 00206 output->getValueObject()->updateData(parentSys->ut); 00207 #endif 00208 00209 return *(output->getValueObject()->getData()); 00210 } 00211 00212 protected: 00213 virtual void mandatoryCleanUp(); 00214 00215 Output<T>* output; 00216 00217 private: 00218 virtual void pushExecutionManager(); 00219 virtual void unsetExecutionManager(); 00220 00221 typedef boost::intrusive::list_member_hook<> connected_hook_type; 00222 connected_hook_type connectedHook; 00223 00224 struct DisconnectDisposer { 00225 void operator() (Input<T>* input) { 00226 input->output = NULL; 00227 } 00228 }; 00229 00230 friend class Output<T>; 00231 DECLARE_HELPER_FRIENDS; 00232 00233 DISALLOW_COPY_AND_ASSIGN(Input); 00234 }; 00235 00236 00237 namespace detail { 00238 template<typename T> struct IntrusiveDelegateFunctor { 00239 //Required types 00240 typedef boost::intrusive::list_member_hook<> hook_type; 00241 typedef hook_type* hook_ptr; 00242 typedef const hook_type* const_hook_ptr; 00243 typedef System::Output<T> value_type; 00244 typedef value_type* pointer; 00245 typedef const value_type* const_pointer; 00246 00247 //Required static functions 00248 static hook_ptr to_hook_ptr(value_type &value); 00249 static const_hook_ptr to_hook_ptr(const value_type &value); 00250 static pointer to_value_ptr(hook_ptr n); 00251 static const_pointer to_value_ptr(const_hook_ptr n); 00252 }; 00253 } 00254 00255 template<typename T> class System::Output : public System::AbstractOutput { 00256 public: 00257 class Value; 00258 00259 Output(System* parent, Value** valueHandle) : AbstractOutput(parent), value(this) { 00260 *valueHandle = &value; 00261 } 00262 virtual ~Output(); 00263 00264 // TODO(dc): How should isConnected() treat delegation? 00265 bool isConnected() const { 00266 return !inputs.empty() || !value.delegators.empty(); 00267 } 00268 00269 protected: 00270 virtual void mandatoryCleanUp(); 00271 00272 Value* getValueObject() { 00273 // TODO(dc): check for cyclic delegation? 00274 Value* v = &value; 00275 while (v->delegate != NULL) { 00276 v = v->delegate; 00277 } 00278 00279 return v; 00280 } 00281 00282 Value value; 00283 00284 private: 00285 virtual void setValueUndefined() { 00286 value.setUndefined(); 00287 } 00288 00289 virtual ExecutionManager* collectExecutionManager() const; 00290 virtual void pushExecutionManager(); 00291 virtual void unsetExecutionManager(); 00292 00293 00294 typename detail::IntrusiveDelegateFunctor<T>::hook_type delegateHook; 00295 00296 typedef boost::intrusive::list<Input<T>, boost::intrusive::member_hook<Input<T>, typename Input<T>::connected_hook_type, &Input<T>::connectedHook> > connected_input_list_type; 00297 connected_input_list_type inputs; 00298 00299 00300 friend class Input<T>; 00301 friend class detail::IntrusiveDelegateFunctor<T>; 00302 DECLARE_HELPER_FRIENDS; 00303 00304 DISALLOW_COPY_AND_ASSIGN(Output); 00305 }; 00306 00307 00308 template<typename T> class System::Output<T>::Value { 00309 public: 00310 void setData(const T* newData) { data = newData; } 00311 void setUndefined() { data = NULL; } 00312 00313 bool isDefined() const { return data != NULL; } 00314 const T* getData() const { return data; } 00315 00316 void delegateTo(Output<T>& delegateOutput); 00317 void undelegate(); 00318 00319 protected: 00320 Output<T>& parentOutput; 00321 Value* delegate; 00322 bool defined; 00323 const T* data; 00324 00325 private: 00326 explicit Value(Output<T>* parent) : parentOutput(*parent), delegate(NULL), data(NULL) {} 00327 00328 bool updateData(update_token_type updateToken) { 00329 assert(parentOutput.parentSys != NULL); // TODO(dc): Is this assertion helpful? 00330 00331 parentOutput.parentSys->update(updateToken); 00332 return isDefined(); 00333 } 00334 00335 typedef boost::intrusive::list<Output<T>, boost::intrusive::function_hook<typename detail::IntrusiveDelegateFunctor<T> > > delegate_output_list_type; 00336 delegate_output_list_type delegators; 00337 00338 struct UndelegateDisposer { 00339 void operator() (Output<T>* output) { 00340 // No need to update the ExecutionManager, this Disposer is only used in ~Output() 00341 //output->unsetExecutionManager(); 00342 output->value.delegate = NULL; 00343 } 00344 }; 00345 00346 friend class Input<T>; 00347 friend class Output<T>; 00348 00349 DISALLOW_COPY_AND_ASSIGN(Value); 00350 }; 00351 00352 00353 #undef DECLARE_HELPER_FRIENDS 00354 00355 00356 } 00357 } 00358 00359 00360 // include template definitions 00361 #include <barrett/systems/abstract/detail/system-inl.h> 00362 00363 // Always include helper definitions to avoid linker errors 00364 #include <barrett/systems/helpers.h> 00365 00366 00367 #endif /* BARRETT_SYSTEMS_ABSTRACT_SYSTEM_H_ */