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 }