ORTS

TerrainBasicImp.H

Go to the documentation of this file.
00001 #ifndef TerrainBasicImp_H
00002 #define TerrainBasicImp_H
00003 
00004 // $Id: TerrainBasicImp.H 5279 2007-06-23 02:49:08Z mburo $
00005 // This is an ORTS file (c) Michael Buro, David Deutscher, licensed under the GPL
00006 
00007 
00008 #include "TerrainBase.H"
00009 #include "GameObj.H"
00010 
00011 /// \brief Implementation of common Task bookkeeping for TerrainBase implementations.
00012 /** 
00013 TerrainBasicImp is templated on a TaskWrapper type, which should include 
00014 a "Task task" member, a TaskWrapper(const Task&) constructor, and any 
00015 other data that the derived implementation needs.
00016 
00017 It maintains a "tasks" container for all TaskWrapper objects, and a queue of 
00018 TaskWrapper iterators pointing on pending (requested but not planned yet) tasks.
00019 Also maintained are maps from TaskId to a TaskWrapper, from an Object* to the
00020 task for moving it, and a multimap from an Object* to all tasks in which it is 
00021 the target of movement.
00022 Derived classes are responsible to remove a TaskWrapper from the pending list,
00023 and for applying some logic to cases where the target object of a task is removed
00024 (dies or vanishes).
00025 
00026 TerrainBasicImp implements: 
00027 add_task, remove_task, cancel_task - as expected.
00028 remove_obj - delete relevant tasks and mappings, if any.
00029 Derived classes that implement these methods should call these ancestor 
00030 versions (of course, call remove/cancal after any code that depends on
00031 the respective data..).
00032 
00033 REGISTER_TYPEOF issue: since this is a template, no REGISTER_TYPEOF's are
00034 done. Users of the class must explicitly use relevant REGISTER_TYPEOF, and
00035 avoid conflicts if using the same TaskWrapper more than once.
00036 The 'REGISTER_TYPEOFS_TerrainBasicImp' macro might be useful.
00037 */
00038 template<class TaskWrapper>
00039 class TerrainBasicImp : public TerrainBase
00040 {
00041 public:
00042   
00043   //---------------------------------------------------------------------
00044   /// \name Internal typedefs
00045   /// public to allow REGISTER_TYPEOF definitions
00046   //---------------------------------------------------------------------
00047   //@{
00048   /* Using a std::list:
00049      1. allows storing iterators, as these are valid even when changing the list.
00050      2. allows fast push_back, fast erase in the middle
00051   */
00052   typedef std::list<TaskWrapper>                            Tasks;
00053   typedef typename Tasks::iterator                          TIter;
00054   /* Using a deque allows FIFO handling of incoming tasks.
00055      The linear find-to-erase operation is tolerable since the queue 
00056      is expected to remain relatively small. */
00057   typedef std::deque<TIter>                                 TaskQueue;
00058   typedef std::map<TerrainBase::TaskId,TIter>               TaskId2Task;
00059   typedef std::map<const Object*,TerrainBase::TaskId>       Obj2TaskId;
00060   typedef std::multimap<const Object*,TerrainBase::TaskId>  ObjIsGoalInTaskId;
00061   //@}
00062   //---------------------------------------------------------------------
00063 
00064 
00065   TerrainBasicImp() {};
00066   TerrainBasicImp(const TerrainBasicImp &other) 
00067     : TerrainBase(other), tasks(other.tasks), pendingTasks(other.pendingTasks), 
00068       taskId2task(other.taskId2task), obj2taskId(other.obj2taskId),
00069       objIsGoalInTaskId(other.objIsGoalInTaskId) {};
00070   virtual ~TerrainBasicImp() {};
00071 
00072   
00073   //---------------------------------------------------------------------
00074   /// \name Implementations for abstract TerrainBase Task-handling methods.
00075   /** Some of the method implementations are empty stubs, allowing derived
00076       classes to call TerrainBasicImp::X() as the first action in each method.
00077       Since this call is needed in remove_obj() (to remove tasks associated with
00078       this object), completeness calls for creating these stubs.
00079   */
00080   //---------------------------------------------------------------------
00081   //@{
00082   virtual TaskId add_task(const TerrainBase::Task &task);
00083   virtual void remove_task(TerrainBase::TaskId tid);
00084   virtual void cancel_task(const Object *obj);
00085 
00086   virtual void add_obj(const Object *obj);
00087   virtual void remove_obj(const Object *obj);
00088   virtual void update_obj(const Object *obj);
00089   virtual void add_segments(const Vector<Segment> &segs);
00090   //@}
00091   //---------------------------------------------------------------------
00092 
00093 
00094 protected:
00095   //---------------------------------------------------------------------
00096   /// \name Internal removal of tasks
00097   /** These methods should be called internally (including by derived classes)
00098       to remove tasks, to differentiate requests by the outside world from internal
00099       bookkeeping. For example, add_task() first removes any existing tasks for
00100       the same objects, but this should not create stop-actions for them, etc.
00101   */
00102   //---------------------------------------------------------------------
00103   //@{
00104   virtual void clean_task_for_obj(const Object *obj);
00105   virtual void clean_task(TerrainBase::TaskId task_id);
00106   //@}
00107   //---------------------------------------------------------------------
00108 
00109   void eraseFromFailed(const TIter& it);
00110   void eraseFromPending(const TIter& it);
00111   void eraseObjIsGoalFor(const typename TaskId2Task::iterator& ti2tIt);
00112 
00113   //---------------------------------------------------------------------
00114   /// \name Internal book-keeping of tasks
00115   //---------------------------------------------------------------------
00116   //@{
00117   Tasks             tasks;
00118   TaskQueue         pendingTasks;
00119   TaskQueue         failedTasks; //not necessarily used in every pathfinder, so probably doesn't belong here, but it was the easiest for now -Nick W.
00120   TaskId2Task       taskId2task;
00121   Obj2TaskId        obj2taskId;
00122   ObjIsGoalInTaskId objIsGoalInTaskId;
00123   //@}
00124   //---------------------------------------------------------------------
00125 
00126 private:
00127   TerrainBasicImp operator=(const TerrainBasicImp&); // don't need it
00128 };
00129 
00130 //---------------------------------------------------------------------
00131 //---------------------------------------------------------------------
00132 
00133 #define REGISTER_TYPEOFS_TerrainBasicImp_OneTime(N,template_arg) \
00134   REGISTER_TYPEOF(N+0, TerrainBasicImp<template_arg>::Obj2TaskId::iterator); \
00135   REGISTER_TYPEOF(N+1, TerrainBasicImp<template_arg>::Obj2TaskId::const_iterator);
00136 //  REGISTER_TYPEOF(N+2, TerrainBasicImp<template_arg>::ObjIsGoalInTaskId::iterator);
00137 //  REGISTER_TYPEOF(N+3, TerrainBasicImp<template_arg>::ObjIsGoalInTaskId::const_iterator);
00138 
00139 #define REGISTER_TYPEOFS_TerrainBasicImp_ForEach(N,template_arg) \
00140   REGISTER_TYPEOF(N+0, TerrainBasicImp<template_arg>::Tasks::iterator); \
00141   REGISTER_TYPEOF(N+1, TerrainBasicImp<template_arg>::Tasks::const_iterator); \
00142   REGISTER_TYPEOF(N+2, TerrainBasicImp<template_arg>::TaskId2Task::iterator); \
00143   REGISTER_TYPEOF(N+3, TerrainBasicImp<template_arg>::TaskId2Task::const_iterator); \
00144   REGISTER_TYPEOF(N+4, TerrainBasicImp<template_arg>::TaskQueue::iterator); \
00145   REGISTER_TYPEOF(N+5, TerrainBasicImp<template_arg>::TaskQueue::const_iterator); \
00146   REGISTER_TYPEOF(N+6, Vector<TerrainBasicImp<template_arg>::TIter>::iterator); \
00147   REGISTER_TYPEOF(N+7, Vector<TerrainBasicImp<template_arg>::TIter>::const_iterator);
00148 
00149 //---------------------------------------------------------------------
00150 template<class TaskWrapper>
00151 TerrainBase::TaskId TerrainBasicImp<TaskWrapper>::add_task(const TerrainBase::Task &task)
00152 {
00153   // These loops of asserts are used to ensure that no module is sending
00154   // a pathfinding request with a vector containing anything other than
00155   // valid GameObj instances. Since this check occurs before the task is
00156   // queued, a failure will occur in the same stack trace that contains
00157   // the faulty code which originally fired the pathfind request Event.
00158 
00159 #ifndef NDEBUG
00160   FORALL(task.objs, o) {
00161     const GameObj * obj = dynamic_cast<const GameObj*>( (*o) );
00162     assert( obj != NULL );
00163   }
00164 #endif
00165 
00166   TaskWrapper tw(task);
00167 
00168 #ifndef NDEBUG  
00169   // These loops of asserts simply guarantee that our TaskWrapper, when
00170   // initialized with a valid Task, in turn has a vector containing 
00171   // nothing but valid GameObj instances.
00172   FORALL(tw.task.objs, o) {
00173     const GameObj * obj = dynamic_cast<const GameObj*>( (*o) );
00174     assert( obj != NULL );
00175   }
00176 #endif
00177   
00178   tw.isPending = true;
00179 
00180   //tasks.push_back(tw);
00181   //TIter pos = tasks.back();
00182   TIter pos = tasks.insert(tasks.end(),tw);
00183   // currently, the taskID is just the address of the allocated taskwrapper in the list.
00184   TerrainBase::TaskId id = (TerrainBase::TaskId)&(*pos);
00185   // insert to the maps
00186   taskId2task[id] = pos;
00187   FORALL(task.objs, objIt) {
00188     clean_task_for_obj(*objIt);
00189     obj2taskId[*objIt] = id;
00190   }
00191   if( task.goal.target == TerrainBase::Goal::OBJ )  {
00192     objIsGoalInTaskId.insert(ObjIsGoalInTaskId::value_type(task.goal.obj, id));
00193   }
00194   
00195   // mark the new task as pending
00196   pendingTasks.push_back(pos);
00197   return id;
00198 }
00199 
00200 //---------------------------------------------------------------------
00201 template<class TaskWrapper>
00202 void TerrainBasicImp<TaskWrapper>::remove_task(TerrainBase::TaskId tid)
00203 {
00204   clean_task(tid);
00205 }
00206 
00207 //---------------------------------------------------------------------
00208 template<class TaskWrapper>
00209 void TerrainBasicImp<TaskWrapper>::cancel_task(const Object *obj)
00210 {
00211   clean_task_for_obj(obj);
00212 }
00213 
00214 //---------------------------------------------------------------------
00215 template<class TaskWrapper>
00216 void TerrainBasicImp<TaskWrapper>::remove_obj(const Object *obj)
00217 {
00218   // remove a task (if any) associated with this object
00219   clean_task_for_obj(obj);
00220   // remove objIsGoalInTaskId associations
00221   objIsGoalInTaskId.erase(obj);
00222 }
00223 
00224 //---------------------------------------------------------------------
00225 template<class TaskWrapper>
00226 void TerrainBasicImp<TaskWrapper>::add_obj(const Object * /*obj*/)
00227 {
00228 }
00229 
00230 //---------------------------------------------------------------------
00231 template<class TaskWrapper>
00232 void TerrainBasicImp<TaskWrapper>::update_obj(const Object * /*obj*/)
00233 {
00234 }
00235 
00236 //---------------------------------------------------------------------
00237 template<class TaskWrapper>
00238 void TerrainBasicImp<TaskWrapper>::add_segments(const Vector<TerrainBase::Segment> &/*segments*/)
00239 {
00240 }
00241 
00242 //---------------------------------------------------------------------
00243 template<class TaskWrapper>
00244 void TerrainBasicImp<TaskWrapper>::clean_task_for_obj(const Object *obj)
00245 {
00246   Obj2TaskId::iterator o2tiIt = obj2taskId.find(obj);
00247   if( o2tiIt == obj2taskId.end() )
00248     return;
00249 
00250   TerrainBase::TaskId taskId = o2tiIt->second;
00251 
00252   typename TaskId2Task::iterator ti2tIt = taskId2task.find(taskId);
00253 
00254   assert(ti2tIt != taskId2task.end());
00255 
00256   // if this is the only object of the task, erase the entire task
00257   if( ti2tIt->second->task.objs.size() <= 1 ) {
00258     eraseObjIsGoalFor(ti2tIt);
00259     eraseFromPending(ti2tIt->second);
00260     eraseFromFailed(ti2tIt->second);
00261     tasks.erase(ti2tIt->second);
00262     taskId2task.erase(ti2tIt);
00263 
00264   // else, remove the object from the task's list of objects
00265   } else {
00266     ti2tIt->second->task.objs.erase(obj);
00267   }
00268 
00269   // remove the obj2TaskId association
00270   obj2taskId.erase(o2tiIt);
00271 }
00272 
00273 //---------------------------------------------------------------------
00274 template<class TaskWrapper>
00275 void TerrainBasicImp<TaskWrapper>::clean_task(TerrainBase::TaskId task_id)
00276 {
00277   typename TaskId2Task::iterator ti2tIt = taskId2task.find(task_id); 
00278 
00279   if( ti2tIt == taskId2task.end() ){
00280     std::cerr << "Tried to clean a task that we don't know about\n";
00281     return;
00282   }
00283 
00284   //  TaskQueue::iterator it = pendingTasks.begin(), end = pendingTasks.end();
00285   //  for (; it != end; ++it);
00286   //#endif   
00287 
00288   // remove obj2TaskId associations
00289   std::set<const Object*>::iterator objIt = ti2tIt->second->task.objs.begin();
00290   std::set<const Object*>::iterator end = ti2tIt->second->task.objs.end();
00291   //  FORALL (ti2tIt->second->task.objs, objIt) {
00292   for (; objIt != end; ++objIt) {
00293     obj2taskId.erase(*objIt);
00294   }
00295 
00296   // remove objIsGoalInTaskId associations
00297   eraseObjIsGoalFor(ti2tIt);
00298 
00299   // remove the task from the pending queue, if it's there
00300   eraseFromPending(ti2tIt->second);
00301  
00302   eraseFromFailed(ti2tIt->second);
00303 
00304   // (find and) remove the task
00305   tasks.erase(ti2tIt->second);
00306 
00307   // remove the taskId2task association
00308   taskId2task.erase(ti2tIt);
00309 }
00310 
00311 //---------------------------------------------------------------------
00312 template<class TaskWrapper>
00313 void TerrainBasicImp<TaskWrapper>::eraseFromPending(const TIter& iter)
00314 {
00315 #if GCC
00316   FORALL (pendingTasks, it) {
00317 #else
00318   typename TaskQueue::iterator it = pendingTasks.begin(), end = pendingTasks.end();
00319   for (; it != end; ++it) {
00320 #endif    
00321     if(*it == iter) {
00322       pendingTasks.erase(it);
00323       break;
00324     }
00325   }
00326 }
00327 
00328 //---------------------------------------------------------------------
00329 template<class TaskWrapper>
00330 void TerrainBasicImp<TaskWrapper>::eraseFromFailed(const TIter& iter)
00331 {
00332 #if GCC
00333   FORALL (failedTasks, it) {
00334 #else
00335   typename TaskQueue::iterator it = failedTasks.begin(), end = failedTasks.end();
00336   for (; it != end; ++it) {
00337 #endif    
00338     if(*it == iter) {
00339       failedTasks.erase(it);
00340       break;
00341     }
00342   }
00343 }
00344 
00345 
00346 
00347 template<class TaskWrapper>
00348 void TerrainBasicImp<TaskWrapper>::eraseObjIsGoalFor(const typename TaskId2Task::iterator& ti2tIt)
00349 {
00350   // shorthand
00351   typedef ObjIsGoalInTaskId::iterator OGIT;
00352 
00353   // If this task has an object as goal
00354   if( ti2tIt->second->task.goal.target == TerrainBase::Goal::OBJ ) {
00355     // find all associations from the goal_obj to tasks
00356     std::pair<OGIT,OGIT> range = objIsGoalInTaskId.equal_range(ti2tIt->second->task.goal.obj);
00357     // remove the one association that refers to the task we're cleaning
00358     for(OGIT i = range.first ; i != range.second ; i++ ) {
00359       if( i->second == ti2tIt->first ) {
00360         objIsGoalInTaskId.erase(i);
00361         break;
00362       }
00363     }
00364   }
00365 }
00366 
00367 #endif


Generated on Fri May 18 2012 03:02:49 for ORTS by Doxygen1.7.3