PLearn 0.1
ParentableObject.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines