Homepage | Demos | Overview | Downloads | Tutorials | Reference | Credits |
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), mcptr(NULL) { 00056 if(ckout) 00057 checkout(); 00058 else 00059 mcptr=(MC_t*)motman->peekMotion(id); 00060 } 00061 00062 //! copy constructor - will reference the same mc_id - checkin/checkouts are NOT independent between this and @a a - they will be linked 00063 MMAccessor(const MMAccessor& a) : mc_id(a.mc_id), mcptr(a.mcptr) {} 00064 00065 //! destructor, checks in if needed 00066 ~MMAccessor() { 00067 while(motman->checkoutLevel(mc_id)>0) 00068 checkin(); 00069 } 00070 00071 //! allows assignment of MMAccessor's, similar to the copy constructor - the two MMAccessor's will control the same MotionCommand 00072 MMAccessor<MC_t> operator=(const MMAccessor<MC_t>& a) { 00073 mc_id=a.mc_id; 00074 mcptr=a.mcptr; 00075 return *this; 00076 } 00077 00078 //! So you can check out if not done by default (or you checked in already) 00079 inline MC_t* checkout() { 00080 return mcptr=dynamic_cast<MC_t*>(motman->checkoutMotion(mc_id)); //!< @test can this be a dynamic_cast? 00081 } 00082 00083 //! Returns the motion command's address so you can call functions 00084 inline MC_t* mc() const { return mcptr; } 00085 00086 //! Checks in the motion 00087 /*! Don't forget, you can also just limit the scope using extra { }'s */ 00088 inline void checkin() { 00089 motman->checkinMotion(mc_id); 00090 } 00091 00092 //! Checks in the motion, passing through the value it is passed. 00093 /*! @return the same value it's passed 00094 * 00095 * Useful in situations like this: 00096 * @code 00097 * MMAccessor<myMC> mine(myMC_id); 00098 * if(mine.mc()->foo()) 00099 * //do something with motman here 00100 * @endcode 00101 * But we want to check in @a mine ASAP - if we don't reference it 00102 * anywhere in the if statement, we're leaving the MC locked longer 00103 * than we need to. How about instead doing this: 00104 * @code 00105 * bool cond; 00106 * {MMAccessor<myMC> mine(myMC_id); cond=mine.mc()->foo();} 00107 * if(cond) 00108 * //do something with motman here 00109 * @endcode 00110 * But that uses an extra variable... ewwww... so use this function 00111 * as a pass through to checkin the MC: 00112 * @code 00113 * MMAccessor<myMC> mine(myMC_id); 00114 * if(mine.checkin(mine.mc()->foo())) 00115 * //do something with motman here 00116 * @endcode*/ 00117 template<class Ret_t> Ret_t checkin(Ret_t ret) { 00118 checkin(); 00119 mcptr=NULL; 00120 return ret; 00121 } 00122 00123 MC_t* operator->() { return mc(); } //!< smart pointer to the underlying MotionCommand 00124 const MC_t* operator->() const { return mc(); } //!< smart pointer to the underlying MotionCommand 00125 MC_t& operator*() { return *mc(); } //!< smart pointer to the underlying MotionCommand 00126 const MC_t& operator*() const { return *mc(); } //!< smart pointer to the underlying MotionCommand 00127 MC_t& operator[](int i) { return mc()[i]; } //!< smart pointer to the underlying MotionCommand 00128 const MC_t& operator[](int i) const { return mc()[i]; } //!< smart pointer to the underlying MotionCommand 00129 00130 protected: 00131 MotionManager::MC_ID mc_id; //!< the MC_ID that this Accessor was constructed with 00132 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) 00133 }; 00134 00135 /*! @file 00136 * @brief Defines MMAccessor, allows convenient ways to check MotionCommands in and out of the MotionManager 00137 * @author ejt (Creator) 00138 * 00139 * $Author: ejt $ 00140 * $Name: tekkotsu-1_4_1 $ 00141 * $Revision: 1.7 $ 00142 * $State: Exp $ 00143 * $Date: 2003/03/09 02:45:23 $ 00144 */ 00145 00146 #endif
Tekkotsu v1.4 |
Generated Sat Jul 19 00:06:31 2003 by Doxygen 1.3.2 |