objdb.cc

Go to the documentation of this file.
00001 /** @file nub/objdb.cc singleton repository that associates each
00002     nub::object with its nub::uid, so that objects can be looked up by
00003     id -- this provides the foundation for using uids as object
00004     handles in a scripting language */
00005 
00006 ///////////////////////////////////////////////////////////////////////
00007 //
00008 // Copyright (c) 1999-2004 California Institute of Technology
00009 // Copyright (c) 2004-2007 University of Southern California
00010 // Rob Peters <rjpeters at usc dot edu>
00011 //
00012 // created: Sun Nov 21 00:26:29 1999
00013 // commit: $Id: objdb.cc 8249 2007-04-12 06:03:40Z rjpeters $
00014 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/objdb.cc $
00015 //
00016 // --------------------------------------------------------------------
00017 //
00018 // This file is part of GroovX.
00019 //   [http://ilab.usc.edu/rjpeters/groovx/]
00020 //
00021 // GroovX is free software; you can redistribute it and/or modify it
00022 // under the terms of the GNU General Public License as published by
00023 // the Free Software Foundation; either version 2 of the License, or
00024 // (at your option) any later version.
00025 //
00026 // GroovX is distributed in the hope that it will be useful, but
00027 // WITHOUT ANY WARRANTY; without even the implied warranty of
00028 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00029 // General Public License for more details.
00030 //
00031 // You should have received a copy of the GNU General Public License
00032 // along with GroovX; if not, write to the Free Software Foundation,
00033 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00034 //
00035 ///////////////////////////////////////////////////////////////////////
00036 
00037 #ifndef GROOVX_NUB_OBJDB_CC_UTC20050626084019_DEFINED
00038 #define GROOVX_NUB_OBJDB_CC_UTC20050626084019_DEFINED
00039 
00040 #include "objdb.h"
00041 
00042 #include "nub/object.h"
00043 #include "nub/weak_handle.h"
00044 
00045 #include "rutz/sfmt.h"
00046 
00047 #include <typeinfo>
00048 #include <map>
00049 
00050 #include "rutz/trace.h"
00051 #include "rutz/debug.h"
00052 GVX_DBG_REGISTER
00053 
00054 using rutz::shared_ptr;
00055 
00056 nub::invalid_uid_error::invalid_uid_error(nub::uid id,
00057                                     const rutz::file_pos& pos)
00058   :
00059   rutz::error(rutz::sfmt("attempted to access invalid object '%ld'",
00060                          id), pos)
00061 {}
00062 
00063 nub::invalid_uid_error::~invalid_uid_error() throw() {}
00064 
00065 ///////////////////////////////////////////////////////////////////////
00066 //
00067 // nub::objectdb::impl definition
00068 //
00069 ///////////////////////////////////////////////////////////////////////
00070 
00071 class nub::objectdb::impl
00072 {
00073 private:
00074   impl(const impl&);
00075   impl& operator=(const impl&);
00076 
00077 public:
00078 
00079   typedef nub::detail::weak_handle<nub::object> obj_ref;
00080 
00081   typedef std::map<nub::uid, obj_ref> map_type;
00082   mutable map_type m_obj_map;
00083 
00084   impl() : m_obj_map() {}
00085 
00086   // Check whether the iterator points to a valid spot in the map, AND
00087   // that it points to a still-living object. If the object has died,
00088   // then we erase the iterator.
00089   bool is_valid_itr(map_type::iterator itr) const throw()
00090   {
00091     if (itr == m_obj_map.end()) return false;
00092 
00093     if (!(*itr).second.is_valid())
00094       {
00095         m_obj_map.erase(itr);
00096         return false;
00097       }
00098 
00099     return true;
00100   }
00101 
00102   bool is_valid_uid(nub::uid id) const throw()
00103     {
00104       map_type::iterator itr = m_obj_map.find(id);
00105       return is_valid_itr(itr);
00106     }
00107 
00108   int count() const throw()
00109     { return m_obj_map.size(); }
00110 
00111   void release(nub::uid id)
00112     {
00113       map_type::iterator itr = m_obj_map.find(id);
00114 
00115       m_obj_map.erase(itr);
00116     }
00117 
00118   void remove(nub::uid id)
00119     {
00120       map_type::iterator itr = m_obj_map.find(id);
00121       if (!is_valid_itr(itr)) return;
00122 
00123       if ( (*itr).second.get()->is_shared() )
00124         throw rutz::error("attempted to remove a shared object", SRC_POS);
00125 
00126       m_obj_map.erase(itr);
00127     }
00128 
00129   // Return the number of items removed
00130   int purge()
00131     {
00132       map_type new_map;
00133 
00134       int num_removed = 0;
00135 
00136       for (map_type::iterator
00137              itr = m_obj_map.begin(),
00138              end = m_obj_map.end();
00139            itr != end;
00140            ++itr)
00141         {
00142           // If the object is shared, we'll be saving the object, so
00143           // copy it into the new_map,
00144           if ( is_valid_itr(itr) && (*itr).second.get()->is_shared() )
00145             {
00146               new_map.insert(*itr);
00147             }
00148           else
00149             {
00150               ++num_removed;
00151             }
00152         }
00153 
00154       // Now swap maps so that the old map gets cleared and everything erased
00155       m_obj_map.swap(new_map);
00156       return num_removed;
00157     }
00158 
00159   void clear_all()
00160     {
00161       m_obj_map.clear();
00162 
00163 #if 0 // an alternate implementation for verbose debugging:
00164       while (!m_obj_map.empty())
00165         {
00166           map_type::iterator it = m_obj_map.begin();
00167 
00168           if ((*it).second.is_valid())
00169             {
00170               dbg_eval_nl(3, typeid(*(*it).second).name());
00171               dbg_eval_nl(3, (*it).second->id());
00172             }
00173 
00174           m_obj_map.erase(it);
00175         }
00176 #endif
00177     }
00178 
00179   nub::object* get_checked_obj(nub::uid id) throw (nub::invalid_uid_error)
00180     {
00181       map_type::iterator itr = m_obj_map.find(id);
00182       if (!is_valid_itr(itr))
00183         {
00184           throw nub::invalid_uid_error(id, SRC_POS);
00185         }
00186 
00187       return (*itr).second.get();
00188     }
00189 
00190   void insert_obj(nub::object* ptr, bool strong)
00191     {
00192       GVX_PRECONDITION(ptr != 0);
00193 
00194       // Check if the object is already in the map
00195       map_type::iterator existing_site = m_obj_map.find(ptr->id());
00196       if (existing_site != m_obj_map.end())
00197         {
00198           // Make sure the existing object is the same as the object
00199           // that we're trying to insert
00200           GVX_ASSERT( (*existing_site).second.get() == ptr );
00201         }
00202 
00203       const int new_id = ptr->id();
00204 
00205       m_obj_map.insert
00206         (map_type::value_type
00207          (new_id, obj_ref(ptr, strong ? nub::STRONG : nub::WEAK)));
00208     }
00209 };
00210 
00211 ///////////////////////////////////////////////////////////////////////
00212 //
00213 // nub::objectdb::iterator definitions
00214 //
00215 ///////////////////////////////////////////////////////////////////////
00216 
00217 namespace
00218 {
00219   class iter_impl :
00220     public rutz::fwd_iter_ifx<nub::object* const>
00221   {
00222   public:
00223     typedef nub::objectdb::impl::map_type map_type;
00224 
00225     void advance_to_valid()
00226     {
00227       while (true)
00228         {
00229           if (m_iter == m_end)
00230             {
00231               m_obj = 0;
00232               return;
00233             }
00234 
00235           if ((*m_iter).second.is_valid())
00236             {
00237               m_obj = (*m_iter).second.get_weak();
00238               return;
00239             }
00240 
00241           map_type::iterator bad = m_iter;
00242           ++m_iter;
00243 
00244           m_map.erase(bad);
00245         }
00246     }
00247 
00248     iter_impl(map_type& m, map_type::iterator itr) :
00249       m_map(m), m_iter(itr), m_obj(0), m_end(m.end())
00250     {
00251       advance_to_valid();
00252     }
00253 
00254     map_type& m_map;
00255     map_type::iterator m_iter;
00256     nub::object* m_obj;
00257     const map_type::iterator m_end;
00258 
00259     virtual ifx_t* clone() const
00260     {
00261       return new iter_impl(m_map, m_iter);
00262     }
00263 
00264     virtual void next()
00265     {
00266       if (!at_end())
00267         {
00268           ++m_iter;
00269           advance_to_valid();
00270         }
00271     }
00272 
00273     virtual value_t& get() const
00274     {
00275       GVX_ASSERT(m_iter == m_end || (*m_iter).second.get_weak() == m_obj);
00276       return m_obj;
00277     }
00278 
00279     virtual bool at_end() const
00280     {
00281       return (m_iter == m_end);
00282     }
00283   };
00284 }
00285 
00286 ///////////////////////////////////////////////////////////////////////
00287 //
00288 // nub::objectdb member definitions
00289 //
00290 ///////////////////////////////////////////////////////////////////////
00291 
00292 nub::objectdb& nub::objectdb::instance()
00293 {
00294   static nub::objectdb* instance = 0;
00295   if (instance == 0)
00296     {
00297       instance = new nub::objectdb;
00298     }
00299   return *instance;
00300 }
00301 
00302 nub::objectdb::iterator nub::objectdb::objects() const
00303 {
00304 GVX_TRACE("nub::objectdb::children");
00305 
00306  return shared_ptr<nub::objectdb::iterator::ifx_t>
00307    (new iter_impl(rep->m_obj_map, rep->m_obj_map.begin()));
00308 }
00309 
00310 nub::objectdb::objectdb() :
00311   rep(new impl)
00312 {
00313 GVX_TRACE("nub::objectdb::objectdb");
00314 }
00315 
00316 nub::objectdb::~objectdb()
00317 {
00318 GVX_TRACE("nub::objectdb::~objectdb");
00319   delete rep;
00320 }
00321 
00322 int nub::objectdb::count() const throw()
00323 {
00324 GVX_TRACE("nub::objectdb::count");
00325 
00326   return rep->count();
00327 }
00328 
00329 bool nub::objectdb::is_valid_uid(nub::uid id) const throw()
00330 {
00331 GVX_TRACE("nub::objectdb::is_valid_uid");
00332   return rep->is_valid_uid(id);
00333 }
00334 
00335 void nub::objectdb::remove(nub::uid id)
00336 {
00337 GVX_TRACE("nub::objectdb::remove");
00338   rep->remove(id);
00339 }
00340 
00341 void nub::objectdb::release(nub::uid id)
00342 {
00343 GVX_TRACE("nub::objectdb::release");
00344   rep->release(id);
00345 }
00346 
00347 void nub::objectdb::purge()
00348 {
00349 GVX_TRACE("nub::objectdb::clear");
00350   dbg_eval_nl(3, typeid(*this).name());
00351   rep->purge();
00352 }
00353 
00354 void nub::objectdb::clear()
00355 {
00356 GVX_TRACE("nub::objectdb::clear");
00357   // Call purge until no more items can be removed
00358   while ( rep->purge() != 0 )
00359     { ; }
00360 }
00361 
00362 void nub::objectdb::clear_on_exit()
00363 {
00364 GVX_TRACE("nub::objectdb::clear_on_exit");
00365   rep->clear_all();
00366 }
00367 
00368 nub::object* nub::objectdb::get_checked_obj(nub::uid id) throw (nub::invalid_uid_error)
00369 {
00370 GVX_TRACE("nub::objectdb::get_checked_obj");
00371   return rep->get_checked_obj(id);
00372 }
00373 
00374 void nub::objectdb::insert_obj(nub::object* obj)
00375 {
00376 GVX_TRACE("nub::objectdb::insert_obj");
00377   rep->insert_obj(obj, true);
00378 }
00379 
00380 void nub::objectdb::insert_obj_weak(nub::object* obj)
00381 {
00382 GVX_TRACE("nub::objectdb::insert_obj_weak");
00383   rep->insert_obj(obj, false);
00384 }
00385 
00386 static const char __attribute__((used)) vcid_groovx_nub_objdb_cc_utc20050626084019[] = "$Id: objdb.cc 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/objdb.cc $";
00387 #endif // !GROOVX_NUB_OBJDB_CC_UTC20050626084019_DEFINED
Generated on Sun May 8 08:41:07 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3