Libbarrett  1.2.4
include/barrett/systems/abstract/system.h
Go to the documentation of this file.
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_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Defines