00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
00066
00067
00068
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
00087
00088
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
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
00143
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
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
00195 map_type::iterator existing_site = m_obj_map.find(ptr->id());
00196 if (existing_site != m_obj_map.end())
00197 {
00198
00199
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
00212
00213
00214
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
00287
00288
00289
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
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 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00387 #endif // !GROOVX_NUB_OBJDB_CC_UTC20050626084019_DEFINED