object_map.cpp

Go to the documentation of this file.
00001 /*
00002  * object_map.cpp
00003  *
00004  * Copyright (C) 2007,2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of the object map (see vgfx.h)
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "vgfx.h"               // always include our own header first!
00036 
00037 #include <sstream>
00038 
00039 #include "common/wave_ex.h"
00040 
00041 
00042 namespace vgfx {
00043 
00044 // destructor implementation
00045 ObjectMap::~ObjectMap(void) throw() { }
00046 
00047 // core registration map
00048 typedef std::map<std::string, smart_ptr<Primitive> > primitive_map_t;
00049 
00050 
00051 
00052 ////////////////////////////////////////////////////////////////////////////////
00053 //
00054 //      static helper methods
00055 //
00056 ////////////////////////////////////////////////////////////////////////////////
00057 
00058 class MapImpl : public ObjectMap {
00059 public:
00060         MapImpl(void) throw();
00061         ~MapImpl(void) throw();
00062 
00063         // public class methods ------------------------------------------------
00064         void initialize(void);
00065 
00066         // vgfx::ObjectMap class interface methods -----------------------------
00067         long size(void) const throw();
00068         void newObjectID(IN const char * prefix,
00069                                 OUT std::string& id);
00070         void addObject(IN smart_ptr<Primitive>&);
00071         Primitive * findObject(IN const char * id) const throw();
00072         smart_ptr<Primitive> removeObject(IN const char * id);
00073 
00074 private:
00075         // private member data -------------------------------------------------
00076         primitive_map_t         m_map;
00077         long                    m_counter;
00078         bool                    m_destroying;
00079 };
00080 
00081 
00082 
00083 MapImpl::MapImpl
00084 (
00085 void
00086 )
00087 throw()
00088 {
00089         m_destroying = false;
00090         m_counter = time(NULL) >> 16;
00091 }
00092 
00093 
00094 
00095 MapImpl::~MapImpl
00096 (
00097 void
00098 )
00099 throw()
00100 {
00101         m_destroying = true;
00102         m_map.clear();
00103 }
00104 
00105 
00106 
00107 void
00108 MapImpl::initialize
00109 (
00110 void
00111 )
00112 {
00113         // nothing to do!
00114 }
00115 
00116 
00117 
00118 void
00119 MapImpl::newObjectID
00120 (
00121 IN const char * prefix,
00122 OUT std::string& id
00123 )
00124 {
00125         if (!prefix) {
00126                 prefix = "obj";
00127         }
00128 
00129         char buffer[64];
00130         while (true) {
00131                 sprintf(buffer, "%s%lx", prefix, m_counter);
00132                 if (!objtree::isValidPropertyName(buffer)) {
00133                         WAVE_EX(wex);
00134                         wex << "Bad prefix--invalid property name: '" << buffer;
00135                         wex << "'";
00136                 }
00137                 ++m_counter;
00138 
00139                 vgfx::Primitive * p = this->findObject(buffer);
00140                 if (!p) {
00141                         id = buffer;
00142                         return;
00143                 }
00144         }
00145 }
00146 
00147 
00148 
00149 long
00150 MapImpl::size
00151 (
00152 void
00153 )
00154 const throw()
00155 {
00156         if (m_destroying)
00157                 return 0;
00158         return m_map.size();
00159 }
00160 
00161 
00162 
00163 void 
00164 MapImpl::addObject
00165 (
00166 IN smart_ptr<Primitive>& p
00167 )
00168 {
00169         ASSERT(!m_destroying, "destroying ourselves");
00170         ASSERT(p, "null primitive passed in to addObject()");
00171         const char * id = p->getID();
00172         ASSERT(id, "object has a null ID");
00173 
00174         if (!objtree::isValidPropertyName(id)) {
00175                 WAVE_EX(wex);
00176                 wex << "Invalid object id: '" << id << "'.  IDs should contain";
00177                 wex << " lower-case letters and numbers only, and must begin ";
00178                 wex << "with a lower-case letter.";
00179         }
00180 
00181         if (this->findObject(id)) {
00182                 WAVE_EX(wex);
00183                 wex << "Already have an object with id '" << id << "'";
00184         }
00185 
00186         m_map[id] = p;
00187 }
00188 
00189 
00190 
00191 Primitive * 
00192 MapImpl::findObject
00193 (
00194 IN const char * id
00195 )
00196 const throw()
00197 {
00198         ASSERT(id, "null ID passed in to findObject()");
00199         if (m_destroying)
00200                 return NULL;
00201 
00202         // is this a good ID?
00203         if (!objtree::isValidPropertyName(id)) {
00204                 WAVE_EX(wex);
00205                 wex << "malformed object id: '" << id << "'";
00206         }
00207 
00208         primitive_map_t::const_iterator i = m_map.find(id);
00209         if (m_map.end() == i) {
00210                 // DPRINTF("  not found!");
00211                 return NULL;    // not found
00212         }
00213 
00214         // found it!
00215         // TODO: why do I have to do this nasty cast?  Necessary?
00216         //   I want to let people do lookups of objects in the registry.
00217         //   The lookup should be const on the registry, even though
00218         //      clients get a non-const object pointer back.
00219         const Primitive * p = i->second;
00220         return (Primitive *) p;
00221 }
00222 
00223 
00224 
00225 smart_ptr<Primitive> 
00226 MapImpl::removeObject
00227 (
00228 IN const char * id
00229 )
00230 {
00231         // actually, there are valid use cases where objects want to
00232         // be removed as the map is destructing.
00233         //ASSERT(!m_destroying, "destroying ourselves");
00234         if (m_destroying) {
00235                 return NULL;    // no-op...
00236         }
00237 
00238         // look up the object
00239         ASSERT(id, "NULL id passed in to removeObject()");
00240         primitive_map_t::iterator i = m_map.find(id);
00241         if (m_map.end() == i) {
00242                 WAVE_EX(wex);
00243                 wex << "Cannot remove object from map: id '" << id;
00244                 wex << "' not found.";
00245         }
00246         smart_ptr<Primitive> p = i->second;
00247         ASSERT(p.get_ref_count() > 1, "Bad ref count?");
00248 
00249         // only allowed to remove if ref count is zero!
00250         long refs = p->getRefCount();
00251         if (refs > 0) {
00252                 WAVE_EX(wex);
00253                 wex << "Cannot remove object '" << id << "' from map: ";
00254                 wex << refs << " object(s) are still using it!";
00255         }
00256 
00257         // save a copy of the primitive before nuking it from map
00258         m_map.erase(i);
00259 //      ASSERT(m_map.end() == m_map.find(id),
00260 //          "Just removed an object, but I can still find it???");
00261 
00262         return p;
00263 }
00264 
00265 
00266 
00267 ////////////////////////////////////////////////////////////////////////////////
00268 //
00269 //      public API
00270 //
00271 ////////////////////////////////////////////////////////////////////////////////
00272 
00273 smart_ptr<ObjectMap>
00274 ObjectMap::create
00275 (
00276 void
00277 )
00278 {
00279         smart_ptr<MapImpl> local = new MapImpl;
00280         ASSERT(local, "out of memory");
00281 
00282         local->initialize();
00283 
00284         return local;
00285 }
00286 
00287 
00288 };      // vgfx namespace
00289