Homepage Demos Overview Downloads Tutorials Reference
Credits
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Search

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), 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