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