object.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /**
00020  * \file object.cpp Implementation of Object (and related) classes
00021  */
00022 
00023 
00024 #include <hn/hnprec.h>
00025 #include <hn/object.h>                           // Interface declarations
00026 #include <hn/log.h>                              // For logging functions
00027 #include <boost/random/mersenne_twister.hpp>     // For random number generator
00028 #include <hn/hydranode.h>                        // for HydraNode::isRunning()
00029 
00030 
00031 //! Random number generator functor
00032 static boost::mt19937 getRandom;
00033 
00034 // Object class
00035 // ------------
00036 IMPLEMENT_EVENT_TABLE(Object, Object*, ObjectEvent);
00037 // Static members
00038 std::map<ObjectId, Object*> Object::s_usedIds;
00039 
00040 // Construction and destruction logic
00041 // On construction, we self-register ourselves with our parent (if existing).
00042 Object::Object(Object *parent, const std::string &name /* = "" */)
00043 : m_parent(parent), m_name(name), m_id(), m_children() {
00044         if (m_parent) {
00045                 m_parent->addChild(this);
00046         }
00047 }
00048 
00049 // On destruction, first call the destructors of all our children, and then
00050 // have parent remove us.
00051 Object::~Object() {
00052         notify(m_id, OBJ_DESTROY);
00053         if (m_parent) {
00054                 m_parent->delChild(this);
00055         }
00056 }
00057 
00058 // Data and operations getters
00059 std::string Object::getName() const {
00060         return m_name;
00061 }
00062 /*virtual*/ uint8_t Object::getDataCount() const {
00063         return 0;
00064 }
00065 /*virtual*/ std::string Object::getData(uint8_t) const {
00066         logTrace(
00067                 TRACE_OBJECT,
00068                 boost::format("%s: Object does not have data.") % m_name
00069         );
00070         return std::string();
00071 }
00072 /*virtual*/ std::string Object::getFieldName(uint8_t) const {
00073         logTrace(
00074                 TRACE_OBJECT,
00075                 boost::format("%s: Object does not heave header information.")
00076                 % m_name
00077         );
00078         return std::string();
00079 }
00080 DataType Object::getFieldType(uint8_t) const { return ODT_UNKNOWN; }
00081 void Object::getValueChoices(std::vector<std::string>*) const {}
00082 /*virtual*/ uint8_t Object::getOperCount() const {
00083         return 0;
00084 }
00085 /*virtual*/ Object::Operation Object::getOper(uint8_t) const {
00086         logTrace(TRACE_OBJECT,
00087                 boost::format("%s: Object does not have operations.") % m_name
00088         );
00089         return Object::Operation();
00090 }
00091 
00092 // Data and operations setters
00093 void Object::setName(const std::string &name) {
00094         m_name = name;
00095 }
00096 /*virtual*/ void Object::doOper(const Object::Operation&) {
00097         logTrace(TRACE_OBJECT,
00098                 boost::format("%s: Object does not have operations.") % m_name
00099         );
00100 }
00101 /*virtual*/ void Object::setData(uint8_t, const std::string&) {
00102         logTrace(
00103                 TRACE_OBJECT,
00104                 boost::format("%s: Object does not have data.") % m_name
00105         );
00106 }
00107 
00108 // Hierarchy traversing
00109 Object* Object::getParent() const { return m_parent; }
00110 uint32_t Object::getChildCount() const {
00111         if (m_children) {
00112                 return m_children->size();
00113         }
00114         return 0;
00115 }
00116 Object* Object::getChild(ObjectId id) const {
00117         if (m_children) {
00118                 CIter i = m_children->find(id);
00119                 if (i == m_children->end()) {
00120                         return 0;
00121                 } else {
00122                         return (*i).second;
00123                 }
00124         }
00125         return 0;
00126 }
00127 bool Object::hasChildren() const {
00128         if (m_children) {
00129                 return m_children->size() > 0;
00130         }
00131         return false;
00132 }
00133 
00134 // Hierarchy modifying
00135 void Object::setParent(Object *newParent) {
00136         if (newParent == 0) {
00137                 throw std::logic_error("Cannot reparent to NULL!");
00138         }
00139 
00140         m_parent->delChild(this);
00141         m_parent = newParent;
00142         newParent->addChild(this);
00143 }
00144 
00145 // Add new child. We generate a new ID for the child which is unique to us
00146 // (however, not unique to the rest of the world).
00147 void Object::addChild(Object *child) {
00148         if (!m_children) {
00149                 m_children = new std::map<ObjectId, Object*>;
00150         }
00151 #ifndef NDEBUG // Generator testing
00152         uint32_t tryCount = 0;
00153         do {
00154                 child->m_id = getRandom();
00155                 ++tryCount;
00156         } while (s_usedIds.find(child->m_id) != s_usedIds.end());
00157         if (tryCount > 1) {
00158                 logTrace(
00159                         TRACE_OBJECT, boost::format(
00160                                 "Took %d trys to generate new identifier."
00161                         ) % tryCount
00162                 );
00163         }
00164 #else
00165         do {
00166                 child->m_id = getRandom();
00167         } while (s_usedIds.find(child->m_id) != s_usedIds.end());
00168 #endif
00169         s_usedIds.insert(std::make_pair(child->m_id, child));
00170 
00171         std::pair<Iter, bool> ret;
00172         ret = m_children->insert(std::make_pair(child->m_id, child));
00173         if (ret.second == false) {
00174                 logDebug(
00175                         "Internal Object error: Already have child with "
00176                         "this ID."
00177                 );
00178         } else {
00179                 logTrace(
00180                         TRACE_OBJECT,
00181                         boost::format("Added child %s(%d)")
00182                         % child->m_name % child->m_id
00183                 );
00184         }
00185         notify(child->m_id, OBJ_ADDED);
00186         // Virtual function call
00187         onChildAdded(child->m_id);
00188 }
00189 
00190 // Remove a child. Note that we do NOT call delete on the child - this function
00191 // is private and is called only from Object destructor - calling delete here
00192 // would cause double deleting.
00193 void Object::delChild(Object *child) {
00194         if (!m_children) {
00195                 logDebug(
00196                         "Internal Object error: Attempt to delete a child "
00197                         "without any childs listed."
00198                 );
00199                 return;
00200         }
00201 
00202         Iter i = m_children->find(child->m_id);
00203         if (i == m_children->end()) {
00204                 logDebug("Object: No such child.");
00205                 return;
00206         }
00207         m_children->erase(i);
00208         if (!m_children->size()) {
00209                 delete m_children;
00210                 m_children = 0;
00211         }
00212         // Virtual function call
00213         onChildRemoved(child->m_id);
00214 
00215         std::map<ObjectId, Object*>::iterator j = s_usedIds.find(child->m_id);
00216         if (j == s_usedIds.end()) {
00217                 logDebug(
00218                         "Internal Object error: Deleting child, but identifier "
00219                         "could not be found."
00220                 );
00221                 return;
00222         }
00223         s_usedIds.erase(j);
00224 }
00225 
00226 // Notifications
00227 void Object::notify(ObjectId source, ObjectEvent event) {
00228         // Optimization: Don't propagate events if we'r not running. This speeds
00229         // up startup/shutdown.
00230         if (HydraNode::instance().isRunning() == false) {
00231                 return;
00232         }
00233         if (m_parent) {
00234                 m_parent->notify(source, event);
00235         }
00236 }
00237 
00238 void Object::notify(ObjectEvent event) {
00239         notify(getId(), event);
00240 }
00241 
00242 // iterator accessors. Note the return values are constant iterators - this
00243 // is to protect our internal structures from unwanted modifications.
00244 Object::CIter Object::begin() const {
00245         if (m_children) {
00246                 return m_children->begin();
00247         } else {
00248                 return 0;
00249         }
00250 }
00251 Object::CIter Object::end() const {
00252         if (m_children) {
00253                 return m_children->end();
00254         } else {
00255                 return 0;
00256         }
00257 }
00258 
00259 // global finder - handy way to quickly find objects w/o surfing through the
00260 // entire hierarchy
00261 /*static*/ Object* Object::findObject(ObjectId id) {
00262         std::map<ObjectId, Object*>::iterator i = s_usedIds.find(id);
00263         if (i == s_usedIds.end()) {
00264                 return 0;
00265         } else {
00266                 return (*i).second;
00267         }
00268 }
00269 
00270 // Convenience functions
00271 void Object::onChildAdded(ObjectId) {}
00272 void Object::onChildRemoved(ObjectId) {}