Homepage | Demos | Overview | Downloads | Tutorials | Reference | Credits |
MMAccessor.hGo to the documentation of this file.00001 #ifndef INCLUDED_MMAccessor_h_ 00002 #define INCLUDED_MMAccessor_h_ 00003 00004 #include "MotionManager.h" 00005 00006 //! This class allows convenient ways of accessing a motion command 00007 /*! Since MotionCommands must be checked out of the motion manager and then checked back 00008 * in when they are done, this is a common source of errors, leading to deadlock. This class 00009 * will check the motion out when it's created, and check it back in when it goes out of scope\n 00010 * It supports recursive checkin/checkouts. \n 00011 * Uses global ::motman 00012 * 00013 * So, instead of doing things like this: 00014 * @code 00015 * YourMotionCommand* ymc = dynamic_cast<YourMotionCommand*>(motman->checkoutMotion(your_mc_id)); 00016 * //do 'stuff' with ymc, e.g.: ymc->rollOver(); 00017 * motman->checkinMotion(your_mc_id); 00018 * @endcode 00019 * ...which can be error prone in many regards - if 'stuff' returns without checking in, or you 00020 * forget to check in, or you get lazy and leave it checked out longer than you should, which can 00021 * cause general performance issues (or worse, deadlock) 00022 * Using MMAccessor makes it much easier to solve these problems, and is easier to code: 00023 * @code 00024 * MMAccessor<YourMotionCommand> mma(your_mc_id); 00025 * //do 'stuff' with mma, e.g.: mma->rollOver(); 00026 * @endcode 00027 * We can call a return at any point and the motion command will automatically be checked in, and 00028 * since C++ guarrantees that the destructor of mma will be called, we don't have to worry about 00029 * forgetting about it. We can limit the scope by placing {}'s around the segment in question: 00030 * @code 00031 * //pre-stuff 00032 * { 00033 * MMAccessor<YourMotionCommand> mma(your_mc_id); 00034 * //do 'stuff' with mma, e.g.: mma->rollOver(); 00035 * } 00036 * //post-stuff - has no knowledge of mma, out of its scope 00037 * @endcode 00038 * And, for those astute enough to notice that the theoretical @a rollOver() function is called on 00039 * MMAccessor when it's actually a member of YourMotionCommand, this is because MMAccessor behaves as a 00040 * 'smart pointer', which overloads operator->() so it is fairly transparent to use. 00041 * 00042 * See also the templated checkin(Ret_t ret) function for more examples of streamlined usage. 00043 * 00044 * MMAccessor is a small class, you may consider passing it around instead of a MotionManager::MC_ID 00045 * if appropriate. (Would be appropriate to avoid multiple checkin/outs in a row from different 00046 * functions, but not as appropriate for storage and reuse of the same MMAccessor. 00047 */ 00048 template<class MC_t> 00049 class MMAccessor { 00050 public: 00051 00052 //! constructor, checks out by default 00053 /*! @param id the motion command to check out 00054 * @param ckout if true (default) will checkout upon creation. otherwise it just gets current address (so you can peek at member fields, which should be safe) */ 00055 MMAccessor(MotionManager::MC_ID id,bool ckout=true) : mc_id(id), checkOutCnt(0), mcptr(NULL) { 00056 if(ckout) 00057 checkout(); 00058 else 00059 mcptr=static_cast<MC_t*>(motman->peekMotion(id)); 00060 } 00061 00062 //! constructor, allows objects to provide uniform access to MotionCommands, regardless of whether they are currently in the MotionManager 00063 MMAccessor(MotionCommand * ptr) : mc_id(invalid_MC_ID), checkOutCnt(0), mcptr(ptr) {} 00064 00065 //! copy constructor - will reference the same mc_id - checkin/checkouts are independent between this and @a a; however, if @a a is checkout out, @c this will check itself out as well 00066 MMAccessor(const MMAccessor& a) : mc_id(a.mc_id), checkOutCnt(0), mcptr(a.mcptr) { 00067 if(a.checkOutCnt>0) 00068 checkout(); 00069 } 00070 00071 //! destructor, checks in if needed 00072 ~MMAccessor() { 00073 while(checkOutCnt>0) 00074 checkin(); 00075 } 00076 00077 //! allows assignment of MMAccessor's, similar to the copy constructor - the two MMAccessor's will control the same MotionCommand 00078 MMAccessor<MC_t> operator=(const MMAccessor<MC_t>& a) { 00079 mc_id=a.mc_id; 00080 mcptr=a.mcptr; 00081 if(motman->isOwner(mc_id)) 00082 checkout(); 00083 return *this; 00084 } 00085 00086 //! So you can check out if not done by default (or you checked in already) 00087 inline MC_t* checkout() { 00088 if(mc_id!=MotionManager::invalid_MC_ID) 00089 mcptr=static_cast<MC_t*>(motman->checkoutMotion(mc_id)); 00090 checkOutCnt++; 00091 return mcptr; 00092 } 00093 00094 //! Returns the motion command's address so you can call functions 00095 inline MC_t* mc() const { return mcptr; } 00096 00097 //! Checks in the motion 00098 /*! Don't forget, you can also just limit the scope using extra { }'s */ 00099 inline void checkin() { 00100 if(checkOutCnt>0) { 00101 motman->checkinMotion(mc_id); 00102 checkOutCnt--; 00103 } 00104 if(checkOutCnt==0) 00105 mcptr=NULL; // fail fast if we use it after last checkin 00106 } 00107 00108 //! Checks in the motion, passing through the value it is passed. 00109 /*! @return the same value it's passed 00110 * 00111 * Useful in situations like this: 00112 * @code 00113 * MMAccessor<myMC> mine(myMC_id); 00114 * if(mine.mc()->foo()) 00115 * //do something with motman here 00116 * @endcode 00117 * But we want to check in @a mine ASAP - if we don't reference it 00118 * anywhere in the if statement, we're leaving the MC locked longer 00119 * than we need to. How about instead doing this: 00120 * @code 00121 * bool cond; 00122 * {MMAccessor<myMC> mine(myMC_id); cond=mine.mc()->foo();} 00123 * if(cond) 00124 * //do something with motman here 00125 * @endcode 00126 * But that uses an extra variable... ewwww... so use this function 00127 * as a pass through to checkin the MC: 00128 * @code 00129 * MMAccessor<myMC> mine(myMC_id); 00130 * if(mine.checkin(mine.mc()->foo())) 00131 * //do something with motman here 00132 * @endcode*/ 00133 template<class Ret_t> Ret_t checkin(Ret_t ret) { 00134 checkin(); 00135 return ret; 00136 } 00137 00138 MC_t* operator->() { return mc(); } //!< smart pointer to the underlying MotionCommand 00139 const MC_t* operator->() const { return mc(); } //!< smart pointer to the underlying MotionCommand 00140 MC_t& operator*() { return *mc(); } //!< smart pointer to the underlying MotionCommand 00141 const MC_t& operator*() const { return *mc(); } //!< smart pointer to the underlying MotionCommand 00142 MC_t& operator[](int i) { return mc()[i]; } //!< smart pointer to the underlying MotionCommand 00143 const MC_t& operator[](int i) const { return mc()[i]; } //!< smart pointer to the underlying MotionCommand 00144 00145 protected: 00146 MotionManager::MC_ID mc_id; //!< the MC_ID that this Accessor was constructed with 00147 unsigned int checkOutCnt; //!< counter so we know how many times checkout was called 00148 MC_t* mcptr; //!< a pointer to the motion command, should always be valid even when not checked out so you can access member fields (which is reasonably safe) 00149 }; 00150 00151 /*! @file 00152 * @brief Defines MMAccessor, allows convenient ways to check MotionCommands in and out of the MotionManager 00153 * @author ejt (Creator) 00154 * 00155 * $Author: ejt $ 00156 * $Name: tekkotsu-2_2 $ 00157 * $Revision: 1.9 $ 00158 * $State: Exp $ 00159 * $Date: 2004/02/18 21:13:02 $ 00160 */ 00161 00162 #endif |
Tekkotsu v2.2 |
Generated Tue Oct 19 14:19:14 2004 by Doxygen 1.3.9.1 |