Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MMAccessor.h

Go 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(MotionManager::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_4_1 $
00157  * $Revision: 1.11 $
00158  * $State: Exp $
00159  * $Date: 2005/08/07 04:11:03 $
00160  */
00161 
00162 #endif

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:47 2005 by Doxygen 1.4.4