Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Namespace Members | Data Fields | Globals

object_visitor.cpp

Go to the documentation of this file.
00001 // See ../license.txt for license information.
00002 //
00003 // object_visitor.cpp
00004 //
00005 // 4-Jul-2003  phamilton  Created
00006 //
00007 
00008 #define REFLECT_IN_LIBRARY_SOURCE
00009 
00010 #include "object_visitor.hpp"
00011 #include <iostream>
00012 #include "../common/object.hpp"
00013 #include "../common/comparable_object.hpp"
00014 #include "../common/outerable_object.hpp"
00015 #include "../common/visitable_object.hpp"
00016 #include "../common/nameable_object.hpp"
00017 #include "../common/pretendable_object.hpp"
00018 #include "member_visitor.hpp"
00019 #include "member.hpp"
00020 #include <boost/bind.hpp>
00021 #include <algorithm>
00022 
00023 using namespace ph::reflect;
00024 
00025 class dump_member_visitor : public ph::common::const_member_visitor
00026 /**
00027         Concrete subclass of member_visitor used to dump the value of a member.
00028 */
00029 {
00030 public:
00031         dump_member_visitor(std::ostream *stream, int indent) :
00032                 _stream(stream), _indent(indent)
00033                         {};
00034                                 
00035         // member_visitor ovverides.
00036         virtual bool visit(const ph::common::object_base *obj, 
00037                 const std::string &name, const ph::common::member_base *member);
00038         
00039 private:
00040         std::ostream *_stream;
00041         int           _indent;
00042 };
00043 
00044 static std::string get_name(const ph::common::object_base *obj)
00045 {
00046         if (!obj->nameable())
00047                 return "object has no nameable interface.";
00048         return obj->nameable()->name();
00049 }
00050 
00051 static std::string get_type(const ph::common::object_base *obj)
00052 {
00053         if (!obj->nameable())
00054                 return "object has no nameable interface.";
00055         return obj->nameable()->type();
00056 }
00057 
00058 static bool obj_equal(const ph::common::object_base *o1, const ph::common::object_base *o2, std::ostream *debug)
00059 {
00060         if (debug)
00061                 *debug << ">> comparing [" << get_name(o1) << "] to [" << get_name(o2) << "]" << std::endl;
00062         
00063         // use equal interface if one exists.
00064         if (o1->comparable())
00065                 return o1->comparable()->equal(o2);
00066         else
00067                 return o1 == o2;
00068 }
00069 
00070 void dump_object_visitor::obj_out(const std::string &msg, const ph::common::object_base *obj)
00071 {
00072         *_stream << ">> " << msg << " [" << get_name(obj) << "]" << std::endl;
00073 }
00074 
00075 void dump_object_visitor::close_stack()
00076 {
00077         if (_debug)
00078                 *_stream << ">> closing stack. " << std::endl;
00079         
00080         // pop the stack back out till it's empty.
00081         while (!_stack.empty())
00082         {
00083                 _stack.pop_back();
00084                 _indent--;
00085                 indent();
00086                 *_stream << "}" << std::endl;
00087         }
00088         if (_indent != 0)
00089                 *_stream << ">> error after closing stack, indent is not 0?. " << std::endl;
00090 }
00091 
00092 void dump_object_visitor::calc_indent(const ph::common::object_base *obj)
00093 {
00094         if (_debug)
00095                 obj_out("calc_indent", obj);
00096 
00097         // we have a new object.
00098         if (!obj->outerable())
00099         {
00100                 if (_debug)
00101                         obj_out("object has no parent interface. Can't calculate the indent.", obj);
00102                 return;
00103         }
00104         
00105         ph::common::object_base *parent = obj->outerable()->outer();
00106         if (parent)
00107         {
00108                 if (_debug)
00109                         obj_out("parent.", parent);
00110                 
00111                 // is the parent on the stack?
00112                 if (std::find_if(_stack.rbegin(), _stack.rend(), 
00113                                 boost::bind(obj_equal, _1, parent, _debug ? _stream : 0)) != _stack.rend())
00114                 {
00115                         if (_debug)
00116                                 obj_out("found parent on stack.", parent);
00117                 
00118                         // pop the stack back till we get the parent.
00119                         while (!obj_equal(_stack.back(), parent, _debug ? _stream : 0))
00120                         {
00121                                 if (_debug)
00122                                         obj_out("popping.", _stack.back());
00123                                 _stack.pop_back();
00124                                 _indent--;
00125                                 indent();
00126                                 *_stream << "}" << std::endl;
00127                         }
00128                         
00129                         if (_debug)
00130                                 obj_out("pushing.", obj);
00131                         _stack.push_back(obj);
00132                 }
00133                 else
00134                 {
00135                         if (_debug)
00136                                 obj_out("not found on stack. pushing.", obj);
00137                         _stack.push_back(obj);
00138                         _indent++;
00139                 }
00140         }
00141         else
00142         {
00143                 if (_debug)
00144                         obj_out("no parent. pushing.", obj);
00145                 close_stack();
00146                 _stack.push_back(obj);
00147         }
00148 }
00149 
00150 void dump_object_visitor::indent()
00151 {
00152         for (int i=0; i<_indent; i++)
00153                 *_stream << " ";
00154 }
00155 
00156 dump_object_visitor::~dump_object_visitor()
00157 {
00158         close_stack();
00159 }
00160 
00161 bool dump_object_visitor::visit(const ph::common::object_base *obj)
00162 {
00163         if (_debug)
00164                 obj_out("visit", obj);
00165         
00166         calc_indent(obj);
00167 
00168         indent();
00169         *_stream << get_type(obj) << "(name=" << get_name(obj) << ") { " << std::endl;
00170         
00171         _indent++;
00172 
00173         // dump members.
00174         dump_member_visitor v(_stream, _indent);
00175         if (obj->visitable())
00176                 obj->visitable()->accept(&v);
00177         else
00178                 obj_out("object can't be reflected.", obj);
00179 
00180         return true;
00181 }
00182 
00183 bool dump_object_visitor::visit_composite(const ph::common::object_base *obj)
00184 {
00185         if (_debug)
00186                 obj_out("visit_composite", obj);
00187 
00188         calc_indent(obj);
00189 
00190         indent();
00191         *_stream << get_name(obj) << " { " << std::endl;
00192 
00193         _indent++;
00194 
00195         return true;
00196 }
00197 
00198 // dump_member_visitor
00199 bool dump_member_visitor::visit(const ph::common::object_base *obj, const std::string &name, 
00200                 const ph::common::member_base *member)
00201 {
00202         // skip over name and type properties
00203         if (name != "name" && name != "type")
00204         {
00205                 for (int i=0; i<_indent; i++)
00206                         *_stream << " ";
00207                 *_stream << name << "=" << member->get() << std::endl;
00208         }
00209         
00210         return true;
00211 }
00212 
00213 bool get_composite_object_visitor::visit_composite(const ph::common::object_base *obj, const ph::common::nameable_object_base *name)
00214 {
00215         if (name->name() == _name)
00216         {       
00217                 // although we don't modify any of the objects we visit, we do
00218                 // need to return the actual object at the end, so
00219                 // we cast out const.
00220                 _obj = const_cast<ph::common::object_base *>(obj);
00221 
00222                 // We check for pretendable objects to make
00223                 // sure that we get the actual object.
00224                 if (_obj->pretendable())
00225                         _obj = _obj->pretendable()->realobject();
00226                         
00227                 return false;
00228         }
00229         return true;
00230 }
00231 
00232 bool get_object_visitor::visit(const ph::common::object_base *obj, const ph::common::nameable_object_base *name)
00233 {
00234         if (name->name() == _name)
00235         {
00236                 // although we don't modify any of the objects we visit, we do
00237                 // need to return the actual object at the end, so
00238                 // we cast out const.
00239                 _obj = const_cast<ph::common::object_base *>(obj);
00240 
00241                 // We check for pretendable objects to make
00242                 // sure that we get the actual object.
00243                 if (_obj->pretendable())
00244                         _obj = _obj->pretendable()->realobject();
00245                         
00246                 return false;
00247         }
00248         return true;
00249 }
00250 
00251 bool get_object_with_type_visitor::visit(const ph::common::object_base *obj, const ph::common::nameable_object_base *name)
00252 {
00253         // the order of these is very important. We often know the name of an object, but
00254         // not it's type, so if the name doesn't match, we don't want to even try to get it's 
00255         // type.
00256         if (name->name() == _name && name->type() == _type)
00257         {
00258                 // although we don't modify any of the objects we visit, we do
00259                 // need to return the actual object at the end, so
00260                 // we cast out const.
00261                 _obj = const_cast<ph::common::object_base *>(obj);
00262 
00263                 // We check for pretendable objects to make
00264                 // sure that we get the actual object.
00265                 if (_obj->pretendable())
00266                         _obj = _obj->pretendable()->realobject();
00267                         
00268                 return false;
00269         }
00270         return true;
00271 }
00272 
00273 bool get_nth_object_visitor::visit(const ph::common::object_base *obj, const ph::common::nameable_object_base *name)
00274 {
00275         // when the index is 0, return the object.
00276         if (_index == 0)
00277         {
00278                 // although we don't modify any of the objects we visit, we do
00279                 // need to return the actual object at the end, so
00280                 // we cast out const.
00281                 _obj = const_cast<ph::common::object_base *>(obj);
00282 
00283                 // We check for pretendable objects to make
00284                 // sure that we get the actual object.
00285                 if (_obj->pretendable())
00286                         _obj = _obj->pretendable()->realobject();
00287                         
00288                 return false;
00289         }
00290         _index--;
00291         return true;
00292 }

Generated on Wed Apr 5 22:03:25 2006 for cppxmlobj by  doxygen 1.4.3