// // $Id: HandleSystem.tcc,v 1.6 2002/08/25 20:24:28 melanson Exp $ // // File: HandleSystem.tcc // Purpose: Create and maintain indirect references to a set of objects. If // the objects move, the indirect references can be kept valid. // Created: 29-OCT-1997 John Hobbs // // $Revision: 1.6 $ // // //----------------------------------------------------------------------------- // // Implement Handle // //----------------------------------------------------------------------------- // Constructors/Destructors template Handle::Handle(const Handle &original): _obj_address(original._obj_address), _theCache(original._theCache) // // Purpose: Instantiate a handle which is a copy of an existing handle. // Make sure that the HandleCache is notified // { if( original._theCache ) _theCache->register_copy(original,*this); } template Handle& Handle::operator =(const Handle &rhs) // // Purpose: Assignment operator. Keep cache up to date. // { _obj_address = rhs._obj_address; _theCache = rhs._theCache; if( _theCache ) _theCache->register_copy(rhs,*this); return *this; } template Handle::~Handle() // // Purpose: Destroy a handle and keep it's cache up-to-date. Do not delete // the object, a handle does not own the object. // { if( _theCache ) _theCache->handle_destroyed(this); _obj_address=0; } // Friends template std::ostream& operator<<(std::ostream& os, const Handle& me) // // Purpose: { os << "Handle points to object at " << (void*)me._obj_address << ". Managed by cache at " << (void*)me._cache << std::endl; return os; } //----------------------------------------------------------------------------- // // Implement HandleCache // //----------------------------------------------------------------------------- // Global definitions template Handle HandleCache::create_handle(int id, T* object) // // Purpose: Create a new handle HIPair pointing to object. The handle can be // looked up as id. // { Handle h(object,this); _id_to_address.insert(IHPair(id,&h)); _address_to_id.insert(cHIPair(&h,id)); return h; } template bool HandleCache::refresh_handle(int id, T*object) // // Purpose: update all occurances of handle id // { typename std::multimap::iterator current =_id_to_address.lower_bound(id); typename std::multimap::iterator stop =_id_to_address.upper_bound(id); if( current != _id_to_address.end() ) { while( current != stop ) { Hptr theHandle = (*current++).second; theHandle->refresh(object); } return true; } else return false; } template bool HandleCache::handle_exists(int id) // // Purpose: Return true if there are any occurances of handle id in the cache // { if( _id_to_address.lower_bound(id) != _id_to_address.end() ) return true; return false; } template void HandleCache::handle_destroyed(Hptr addr) // // Purpose: No longer track this handle. The internal pointers of all // instances are zeroed. // { typename std::multimap::iterator ele=_address_to_id.find(addr); if( ele != _address_to_id.end() ) { int id = (*ele).second; _address_to_id.erase(ele); typename std::multimap::iterator current =_id_to_address.lower_bound(id); typename std::multimap::iterator stop =_id_to_address.upper_bound(id); bool found=false; while( !found && current != stop ) { if( (*current).second == addr ) { _id_to_address.erase(current); found = true; } else ++current; } } } template void HandleCache::register_copy(const Handle &hold, Handle &hnew) // // Purpose: Somewhere hold has been used to create hnew. Include hnew // in the cache // { typename std::multimap::iterator i = _address_to_id.find((Hptr)&hold); int id = (*i).second; _address_to_id.insert(cHIPair(&hnew,id)); _id_to_address.insert(IHPair(id,&hnew)); } // Constructors/Destructors template HandleCache::~HandleCache() // // Purpose: Destroy the cache. Zero the internal pointer of all active handles // If any active handles are later dereferenced, it is considered an // error. // { typename std::multimap::iterator i=_address_to_id.begin(), iend=_address_to_id.end(); while( i != iend ) { Hptr hptr = (*(i++)).first; hptr->refresh(0); // This handle is no longer sync'd. If used, it's } // an error. } // Friends template std::ostream& operator<<(std::ostream& os, const HandleCache& me) // // Purpose: // { os << "Printing handle cache at " << (void *)&me << std::endl; typename std::multimap*,T>::const_iterator i = me._address_to_id.begin(); while( i != me._address_to_id.end() ) { Handle* hptr = (*i).first; T x = **hptr; os << " Handle id = " << (*i).second << ", address = " << (*i).first << ", Value = " << x << std::endl; ++i; } return os; }