PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // ParentableObject.cc 00004 // 00005 // Copyright (C) 2005-2006 Nicolas Chapados 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 /* ******************************************************* 00036 * $Id: .pyskeleton_header 544 2003-09-01 00:05:31Z plearner $ 00037 ******************************************************* */ 00038 00039 // Authors: Nicolas Chapados 00040 00043 #define PL_LOG_MODULE_NAME "ParentableObject" 00044 00045 #include "ParentableObject.h" 00046 #include <plearn/base/ObjectGraphIterator.h> 00047 #include <plearn/base/stringutils.h> 00048 #include <plearn/io/pl_log.h> 00049 00050 namespace PLearn { 00051 using namespace std; 00052 00053 PLEARN_IMPLEMENT_ABSTRACT_OBJECT( 00054 ParentableObject, 00055 "Object which maintains a \"parent\" pointer as part of an object graph.", 00056 "The purpose of ParentableObject is to facilitate the building of complex\n" 00057 "graphs of Objects. The basic ideas are as follows:\n" 00058 "\n" 00059 "- The object contains a member called parent, which is simply a\n" 00060 " backpointer to the \"parent\" object in the graph. This is a dumb\n" 00061 " pointer to avoid cycles as the forward pointers will usually be PP's.\n" 00062 "\n" 00063 "- The build_() method looks at all the options of itself, and for those\n" 00064 " objects that are ParentableObject, it sets their parent pointer\n" 00065 " to this. (This mechanism could conceptually be put in Object\n" 00066 " itself, but out of caution we leave it in ParentableObject for now).\n" 00067 "\n" 00068 "In other words, this class both provides the backpointer in an object\n" 00069 "graph, and provides the mechanism to update the backpointer according to\n" 00070 "arbitrary forward pointers (as long as the forward pointers are accessible\n" 00071 "as options through an ObjectOptionsIterator.)\n" 00072 "\n" 00073 "Each ParentableObject can be marked with the kind of parent it wants. The\n" 00074 "following kinds are supported:\n" 00075 "\n" 00076 "- AnyParent : anybody that calls setParent gets to be the parent.\n" 00077 "\n" 00078 "- WeakParent : the first caller to setParent gets to be the parent, the\n" 00079 " other ones are ignored (default).\n" 00080 "\n" 00081 "- UniqueParent : the first caller to setParent gets to be the parent, the\n" 00082 " other ones yield PLERRORs.\n" 00083 ); 00084 00085 ParentableObject::ParentableObject(bool adoptive_parent, ParentKind pk) 00086 : m_parent(0), m_adoptive_parent(adoptive_parent), m_parent_kind(pk) 00087 { } 00088 00089 // ### Nothing to add here, simply calls build_ 00090 void ParentableObject::build() 00091 { 00092 inherited::build(); 00093 build_(); 00094 } 00095 00096 void ParentableObject::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00097 { 00098 inherited::makeDeepCopyFromShallowCopy(copies); 00099 00100 deepCopyField(m_parent, copies); 00101 } 00102 00103 void ParentableObject::declareMethods(RemoteMethodMap& rmm) 00104 { 00105 // Insert a backpointer to remote methods; note that this 00106 // different than for declareOptions() 00107 rmm.inherited(inherited::_getRemoteMethodMap_()); 00108 00109 declareMethod( 00110 rmm, "getParent", (const Object* (ParentableObject::*)() const)&ParentableObject::parent, 00111 (BodyDoc("Return the parent object"))); 00112 00113 declareMethod( 00114 rmm, "setParent", &ParentableObject::setParent, 00115 (BodyDoc("Setter for the parent object"), 00116 ArgDoc ("parent", "Pointer to the new parent of this object"))); 00117 00118 declareMethod( 00119 rmm, "checkParent", &ParentableObject::checkParent, 00120 (BodyDoc("After the m_parent field of a child has been set, this function is\n" 00121 "called so that the child has a chance to check the parent (e.g. dynamic\n" 00122 "type checking). By default it just asserts that there is a parent."))); 00123 } 00124 00125 void ParentableObject::build_() 00126 { 00127 updateChildrensParent(this); 00128 } 00129 00130 void ParentableObject::updateChildrensParent(Object* parent) 00131 { 00132 if (! m_adoptive_parent) { 00133 // Set the backpointers of sub-objects under the current object to 00134 // this. Skip nonparentable options. 00135 for (ObjectOptionsIterator it(this), end ; it != end ; ++it) 00136 { 00137 if (it.getCurrentOptionFlags() & OptionBase::nonparentable) 00138 continue; 00139 00140 if (const ParentableObject* cpo = dynamic_cast<const ParentableObject*>(*it)) { 00141 ParentableObject* po = const_cast<ParentableObject*>(cpo); 00142 po->setParent(parent); 00143 if (parent) 00144 po->checkParent(); 00145 } 00146 } 00147 } 00148 } 00149 00150 void ParentableObject::setParent(Object* parent) 00151 { 00152 if (m_parent == parent) 00153 return; 00154 00155 // Behave appropriately according to the type of parent we want 00156 switch (m_parent_kind) { 00157 case AnyParent: 00158 break; 00159 00160 case WeakParent: 00161 if (m_parent) { 00162 MODULE_LOG << "Object at " << ((void*)this) 00163 << " (" << left(classname(),30) << ") " 00164 << " ignoring candidate weak parent " << ((void*)parent) 00165 << " (" << (parent? parent->classname() : string("NULL")) << ") " 00166 << endl; 00167 return; 00168 } 00169 break; 00170 00171 case UniqueParent: 00172 if (m_parent) // Because of test above, m_parent != parent 00173 PLERROR("ParentableObject::setParent: for object at 0x%p (%s),\n" 00174 "trying to override existing parent at 0x%p (%s) with\n" 00175 "new parent at 0x%p (%s) -- parenting mode set to UniqueParent.", 00176 (void*)this, classname().c_str(), 00177 (void*)m_parent, m_parent->classname().c_str(), 00178 (void*)parent, (parent? parent->classname().c_str() : "NULL")); 00179 break; 00180 } 00181 00182 // Do some logging 00183 if (m_parent) { 00184 MODULE_LOG << "Object at " << ((void*)this) 00185 << " (" << left(classname(),30) << ") " 00186 << " getting parent " << ((void*)parent) 00187 << " (" << (parent? parent->classname() : string("NULL")) << ") " 00188 << " overriding previous " << ((void*)m_parent) 00189 << " (" << m_parent->classname() << ") " 00190 << endl; 00191 } 00192 else { 00193 MODULE_LOG << "Object at " << ((void*)this) 00194 << " (" << left(classname(),30) << ") " 00195 << " getting parent " << ((void*)parent) 00196 << " (" << (parent? parent->classname() : string("NULL")) << ") " 00197 << endl; 00198 } 00199 00200 m_parent = parent; 00201 } 00202 00203 void ParentableObject::checkParent() const 00204 { 00205 PLASSERT( m_parent ); 00206 } 00207 00208 00209 //##### TransparentParentable ############################################### 00210 00211 PLEARN_IMPLEMENT_ABSTRACT_OBJECT( 00212 TransparentParentable, 00213 "Special type of ParentableObject that cannot act as a visible parent.", 00214 "Suppose that you have the following object structure:\n" 00215 "\n" 00216 " MasterManager contains a list of ObjectDescriptor\n" 00217 " Each ObjectDescriptor contains a list of ChildrenObject\n" 00218 "\n" 00219 "The idea here is that ObjectDescriptor is a simple holder class that\n" 00220 "provides additional information for how ChildrenObject should be built in\n" 00221 "the context of MasterManager. However, we want to have the situation\n" 00222 "wherein the parent() of each ChildrenObject is the MasterManager, and not\n" 00223 "the ObjectDescriptors.\n" 00224 "\n" 00225 "That's the purpose of TransparentParentable: if you make ObjectDescriptor a\n" 00226 "derived class of TransparentParentable, they are skipped when going up on\n" 00227 "the children-parent paths.\n" 00228 ); 00229 00230 TransparentParentable::TransparentParentable(bool adoptive_parent, ParentKind pk) 00231 : inherited(adoptive_parent, pk) 00232 { } 00233 00234 // ### Nothing to add here, simply calls build_ 00235 void TransparentParentable::build() 00236 { 00237 inherited::build(); 00238 build_(); 00239 } 00240 00241 void TransparentParentable::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00242 { 00243 inherited::makeDeepCopyFromShallowCopy(copies); 00244 } 00245 00246 void TransparentParentable::build_() 00247 { } 00248 00249 void TransparentParentable::updateChildrensParent(Object* the_parent) 00250 { 00251 if (the_parent == this) 00252 // parent() may be null -- this is fine 00253 inherited::updateChildrensParent(parent()); 00254 else 00255 inherited::updateChildrensParent(the_parent); 00256 } 00257 00258 void TransparentParentable::setParent(Object* parent) 00259 { 00260 // Set it for ourselves and our children 00261 inherited::setParent(parent); 00262 updateChildrensParent(parent); 00263 } 00264 00265 void TransparentParentable::checkParent() const 00266 { 00267 // Forward the call to sub-objects 00268 for (ObjectOptionsIterator it(this), end ; it != end ; ++it) 00269 { 00270 if (it.getCurrentOptionFlags() & OptionBase::nonparentable) 00271 continue; 00272 00273 if (const ParentableObject* po = dynamic_cast<const ParentableObject*>(*it)) 00274 const_cast<ParentableObject*>(po)->checkParent(); 00275 } 00276 } 00277 00278 00279 } // end of namespace PLearn 00280 00281 00282 /* 00283 Local Variables: 00284 mode:c++ 00285 c-basic-offset:4 00286 c-file-style:"stroustrup" 00287 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00288 indent-tabs-mode:nil 00289 fill-column:79 00290 End: 00291 */ 00292 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :