Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

Object.cc

Go to the documentation of this file.
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal 00006 // Copyright (C) 2002 Frederic Morin 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 00037 00038 00039 /* ******************************************************* 00040 * $Id: Object.cc,v 1.30 2004/07/21 16:30:50 chrish42 Exp $ 00041 * AUTHORS: Pascal Vincent & Yoshua Bengio 00042 * This file is part of the PLearn library. 00043 ******************************************************* */ 00044 00045 #include "Object.h" 00046 #include "stringutils.h" 00047 #include <plearn/io/fileutils.h> 00048 #include "TypeFactory.h" 00049 //#include <iostream> 00050 00051 #include <algorithm> 00052 00053 namespace PLearn { 00054 using namespace std; 00055 00056 Object::Object() 00057 {} 00058 00059 PLEARN_IMPLEMENT_OBJECT(Object, "Base class for PLearn Objects", "NO HELP"); 00060 00061 // by default, do nothing... 00062 void Object::makeDeepCopyFromShallowCopy(map<const void*, void*>& copies) 00063 {} 00064 00065 void Object::setOption(const string& optionname, const string& value) 00066 { 00067 istrstream in_(value.c_str()); 00068 PStream in(&in_); 00069 readOptionVal(in, optionname); 00070 } 00071 00072 string Object::getOption(const string &optionname) const 00073 { 00074 ostrstream out_; 00075 PStream out(&out_); 00076 writeOptionVal(out, optionname); 00077 char* buf = out_.str(); 00078 int n = out_.pcount(); 00079 string s(buf,n); 00080 out_.freeze(false); // return ownership to the stream, so that it may free it... 00081 return removeblanks(s); 00082 } 00083 00084 void Object::changeOptions(const map<string,string>& name_value) 00085 { 00086 map<string,string>::const_iterator it = name_value.begin(); 00087 map<string,string>::const_iterator itend = name_value.end(); 00088 while(it!=itend) 00089 { 00090 setOption(it->first, it->second); 00091 ++it; 00092 } 00093 } 00094 00095 void Object::changeOption(const string& optionname, const string& value) 00096 { 00097 map<string,string> name_value; 00098 name_value[optionname] = value; 00099 changeOptions(name_value); 00100 } 00101 00102 void Object::build_() 00103 {} 00104 00105 void Object::build() 00106 {} 00107 00108 string Object::info() const { return classname(); } 00109 00110 void Object::print(ostream& out) const 00111 { 00112 PStream pout(&out); 00113 pout << *this << endl; 00114 //out << '{' << info() << "} "; 00115 } 00116 00117 00118 void Object::readOptionVal(PStream &in, const string &optionname) 00119 { 00120 try 00121 { 00122 OptionList &options = getOptionList(); 00123 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00124 { 00125 if ((*it)->optionname() == optionname) 00126 { 00127 (*it)->read(this, in); 00128 return; 00129 } 00130 } 00131 00132 // Found no options matching 'optionname'. First look for brackets. If there 00133 // are brackets, they must be located before any dot. 00134 size_t lb_pos = optionname.find('['); 00135 size_t rb_pos = optionname.find(']'); 00136 size_t dot_pos = optionname.find('.'); 00137 if (rb_pos != string::npos) 00138 { 00139 if (lb_pos == string::npos) 00140 PLERROR("Object::readOptionVal() - Unmatched brackets"); 00141 string optname = optionname.substr(0, lb_pos); 00142 if (dot_pos == string::npos || rb_pos < dot_pos) 00143 { 00144 int i = toint(optionname.substr(lb_pos + 1, rb_pos - lb_pos - 1)); 00145 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00146 if ((*it)->optionname() == optname) 00147 { 00148 (*it)->getIndexedObject(this, i)->readOptionVal(in, optionname.substr(rb_pos + 2)); 00149 return; 00150 } 00151 } 00152 } 00153 else if (lb_pos != string::npos) 00154 PLERROR("Object::readOptionVal() - Unmatched brackets"); 00155 00156 // No brackets, look for a dot 00157 if (dot_pos != string::npos) 00158 { 00159 // Found a dot, assume it's a field with an Object * field 00160 string optname = optionname.substr(0, dot_pos); 00161 string optoptname = optionname.substr(dot_pos + 1); 00162 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00163 if ((*it)->optionname() == optname) 00164 { 00165 (*it)->getAsObject(this)->readOptionVal(in, optoptname); 00166 return; 00167 } 00168 } 00169 } 00170 catch(const PLearnError& e) 00171 { 00172 PLERROR("Problem while attempting to read value of option %s of a %s:\n %s", 00173 optionname.c_str(), classname().c_str(), e.message().c_str()); 00174 } 00175 00176 // There are bigger problems in the world but still it isn't always funny 00177 PLERROR("There is no option named %s in a %s", optionname.c_str(),classname().c_str()); 00178 } 00179 00180 void 00181 Object::writeOptionVal(PStream &out, const string &optionname) const 00182 { 00183 OptionList &options = getOptionList(); 00184 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00185 if ((*it)->optionname() == optionname) { 00186 (*it)->write(this, out); 00187 return; 00188 } 00189 00190 // Found no options matching 'optionname'. First look for brackets. If there 00191 // are brackets, they must be located before any dot. 00192 size_t lb_pos = optionname.find('['); 00193 size_t rb_pos = optionname.find(']'); 00194 size_t dot_pos = optionname.find('.'); 00195 if (rb_pos != string::npos) { 00196 if (lb_pos == string::npos) 00197 PLERROR("Object::writeOptionVal() - Unmatched brackets"); 00198 string optname = optionname.substr(0, lb_pos); 00199 if (dot_pos == string::npos || rb_pos < dot_pos) { 00200 int i = toint(optionname.substr(lb_pos + 1, rb_pos - lb_pos - 1)); 00201 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00202 if ((*it)->optionname() == optname) { 00203 (*it)->getIndexedObject(this, i)->writeOptionVal(out, optionname.substr(rb_pos + 2)); 00204 return; 00205 } 00206 } 00207 } else if (lb_pos != string::npos) 00208 PLERROR("Object::writeOptionVal() - Unmatched brackets"); 00209 00210 // No brackets, look for a dot 00211 if (dot_pos != string::npos) { 00212 // Found a dot, assume it's a field with an Object * field 00213 string optname = optionname.substr(0, dot_pos); 00214 string optoptname = optionname.substr(dot_pos + 1); 00215 for (OptionList::iterator it = options.begin(); it != options.end(); ++it) 00216 if ((*it)->optionname() == optname) { 00217 (*it)->getAsObject(this)->writeOptionVal(out, optoptname); 00218 return; 00219 } 00220 } 00221 // There are bigger problems in the world but still it isn't always funny 00222 PLERROR("Object::writeOptionVal() - Unknown option \"%s\"", optionname.c_str()); 00223 } 00224 00225 00226 string Object::getOptionsToSave() const 00227 { 00228 string res = ""; 00229 OptionList& options = getOptionList(); 00230 00231 for( OptionList::iterator it = options.begin(); it!=options.end(); ++it ) 00232 { 00233 OptionBase::flag_t flags = (*it)->flags(); 00234 if(!(flags & OptionBase::nosave)) 00235 res += (*it)->optionname() + " "; 00236 } 00237 return res; 00238 } 00239 00240 00241 void Object::newread(PStream &in) 00242 { 00243 string cl; 00244 in.getline(cl, '('); 00245 cl = removeblanks(cl); 00246 if (cl != classname()) 00247 PLERROR("Object::newread() - Was expecting \"%s\", but read \"%s\"", 00248 classname().c_str(), cl.c_str()); 00249 00250 in.skipBlanksAndComments(); 00251 int c = in.get(); 00252 if (c != ')') 00253 { 00254 in.unget(); 00255 for (;;) 00256 { 00257 // Read all specified options 00258 string optionname; 00259 in.getline(optionname, '='); 00260 optionname = removeblanks(optionname); 00261 in.skipBlanksAndComments(); 00262 00263 OptionList &options = getOptionList(); 00264 OptionList::iterator it = find_if(options.begin(), options.end(), 00265 bind2nd(mem_fun(&OptionBase::isOptionNamed), optionname)); 00266 // if (it != options.end() && ((*it)->flags() & in.option_flags_in) == 0) 00267 if (it!=options.end() && (*it)->shouldBeSkipped() ) 00268 (*it)->read_and_discard(in); 00269 else 00270 readOptionVal(in, optionname); 00271 00272 in.skipBlanksAndCommentsAndSeparators(); 00273 if (in.peek() == ')') 00274 { 00275 in.get(); 00276 break; 00277 } 00278 } 00279 } 00280 build(); // Build newly read Object 00281 } 00282 00283 void Object::newwrite(PStream &out) const 00284 { 00285 vector<string> optnames = split(getOptionsToSave()); 00286 out.write(classname()); 00287 out.write("(\n"); 00288 for (size_t i = 0; i < optnames.size(); ++i) 00289 { 00290 out.write(optnames[i]); 00291 out.write(" = "); 00292 writeOptionVal(out, optnames[i]); 00293 if (i < optnames.size() - 1) 00294 out.write(";\n"); 00295 } 00296 out.write(" )\n"); 00297 } 00298 00299 00300 void Object::write(ostream& out_) const 00301 { 00302 PStream out(&out_); 00303 newwrite(out); 00304 } 00305 00306 void Object::read(istream& in_) 00307 { 00308 in_ >> ws; // skip blanks 00309 int c = in_.peek(); 00310 if(c=='<') // --> it's an "old-style" <Classname> ... </Classname> kind of definition 00311 oldread(in_); 00312 else { // assume it's a "new-style" Classname(...) 00313 PStream in(&in_); 00314 newread(in); 00315 } 00316 } 00317 00318 00319 void Object::call(const string& methodname, int nargs, PStream& in_parameters, PStream& out_results) 00320 { 00321 PLERROR("In Object::call no method named %s supported by this object's call method.", methodname.c_str()); 00322 } 00323 00324 void Object::run() 00325 { PLERROR("Not a runnable Object"); } 00326 00327 void Object::oldread(istream& in) 00328 { PLERROR("oldread method not implemented for this object"); } 00329 00330 void Object::save(const string& filename) const 00331 { PLearn::save(filename, *this); } 00332 00333 void Object::load(const string& filename) 00334 { PLearn::load(filename, *this); } 00335 00336 Object::~Object() 00337 {} 00338 00339 00340 Object* loadObject(const string &filename) 00341 { 00342 ifstream in_(filename.c_str()); 00343 if (!in_) 00344 PLERROR("loadObject() - Could not open file \"%s\" for reading", filename.c_str()); 00345 00346 PStream in(&in_); 00347 Object *o = readObject(in); 00348 o->build(); 00349 return o; 00350 } 00351 00352 Object* macroLoadObject(const string &filename, map<string, string>& vars) 00353 { 00354 string script = readFileAndMacroProcess(filename, vars); 00355 PIStringStream sin(script); 00356 Object* o = readObject(sin); 00357 o->build(); 00358 return o; 00359 } 00360 00361 Object* macroLoadObject(const string &filename) 00362 { 00363 map<string, string> vars; 00364 return macroLoadObject(filename,vars); 00365 } 00366 00367 Object* readObject(PStream &in, unsigned int id) 00368 { 00369 Object *o=0; 00370 in.skipBlanksAndCommentsAndSeparators(); 00371 00372 //pl_streambuf* buf = dynamic_cast<pl_streambuf*>(in.rdbuf()); 00373 pl_streammarker fence(in.pl_rdbuf()); 00374 00375 int c = in.peek(); 00376 if (c == '<') // Old (deprecated) serialization mode 00377 { 00378 in.get(); // Eat '<' 00379 string cl; 00380 in.getline(cl, '>'); 00381 cl = removeblanks(cl); 00382 if (cl == "null") 00383 return 0; 00384 size_t p = cl.find(":"); 00385 if (p != string::npos) 00386 cl = cl.substr(0, p); 00387 o = TypeFactory::instance().newObject(cl); 00388 if (!o) 00389 PLERROR("readObject() - Type \"%s\" not declared in TypeFactory map (did you do a proper DECLARE_NAME_AND_DEEPCOPY?)", cl.c_str()); 00390 // Go back before the header starts 00391 in.pl_rdbuf()->seekmark(fence); 00392 o->read(in._do_not_use_this_method_rawin_()); 00393 } 00394 else if (c == '*') // Pointer to object 00395 { 00396 in >> o; 00397 } 00398 else if(c == '`') // back-quote: reference to an object in another file 00399 { 00400 in.get(); // skip the opening back-quote 00401 string fname; 00402 in.getline(fname,'`'); 00403 fname = removeblanks(fname); 00404 // TODO: Check if this is really what we want 00405 // (ie: We could want to use the options 00406 // of 'in' to load the object...) 00407 o = loadObject(fname); 00408 } 00409 else // It must be a Classname(...) kind of definition 00410 { 00411 string cl; 00412 in.getline(cl, '('); 00413 cl = removeblanks(cl); 00414 // It's a Classname(opt1 = ...; ...; optn = ...); --> calls newread() 00415 o = TypeFactory::instance().newObject(cl); 00416 if (!o) 00417 PLERROR("readObject() - Type \"%s\" not declared in TypeFactory map (did you do a proper DECLARE_NAME_AND_DEEPCOPY?)", cl.c_str()); 00418 in.pl_rdbuf()->seekmark(fence); 00419 o->newread(in); 00420 } 00421 00422 if (id != UINT_MAX) 00423 in.copies_map_in[id] = o; 00424 return o; 00425 } 00426 00427 00428 PStream& operator>>(PStream& in, Object*& x) 00429 { 00430 in.skipBlanksAndCommentsAndSeparators(); 00431 if (in.peek() == '*') 00432 { 00433 in.get(); // Eat '*' 00434 unsigned int id; 00435 in >> id; 00436 in.skipBlanksAndCommentsAndSeparators(); 00437 if (id==0) 00438 x = 0; 00439 else if (in.peek() == '-') 00440 { 00441 in.get(); // Eat '-' 00442 char cc = in.get(); 00443 if(cc != '>') // Eat '>' 00444 PLERROR("In PStream::operator>>(Object*&) Wrong format. Expecting \"*%d->\" but got \"*%d-%c\".", id, id, cc); 00445 in.skipBlanksAndCommentsAndSeparators(); 00446 if(x) 00447 in >> *x; 00448 else // x is null 00449 x = readObject(in, id); 00450 in.skipBlanksAndCommentsAndSeparators(); 00451 in.copies_map_in[id]= x; 00452 } 00453 else 00454 { 00455 // Find it in map and return ptr; 00456 map<unsigned int, void *>::iterator it = in.copies_map_in.find(id); 00457 if (it == in.copies_map_in.end()) 00458 PLERROR("In PStream::operator>>(Object*&) object (ptr) to be read has not been previously defined"); 00459 x= static_cast<Object *>(it->second); 00460 } 00461 } 00462 else 00463 { 00464 x = readObject(in); 00465 in.skipBlanksAndCommentsAndSeparators(); 00466 } 00467 00468 return in; 00469 } 00470 00471 00472 00473 /* 00474 PStream& operator>>(PStream &in, Object * &o) 00475 { 00476 if (in.peek() == '*') { 00477 in.get(); // Eat '*' 00478 unsigned int id; 00479 in >> raw >> id; 00480 if (in.peek() == '-') { 00481 in.get(); // Eat '-' 00482 in.get(); // Eat '>' 00483 // Read object 00484 // NOTE: Object is added immediately to the map before any build() is called on it. 00485 o = readObject(in, id); 00486 } else { 00487 // Find it in map and return ptr 00488 map<unsigned int, void *>::iterator it = in.copies_map_in.find(id); 00489 if (it == in.copies_map_in.end()) 00490 PLERROR("read() - Object to be read has not been previously defined"); 00491 o = static_cast<Object *>(it->second); 00492 } 00493 } else { 00494 o = readObject(in); 00495 } 00496 return in; 00497 } 00498 */ 00499 00500 } // end of namespace PLearn 00501 00502 00504 extern "C" 00505 { 00506 void printobj(PLearn::Object* p) 00507 { 00508 PLearn::PStream perr(&std::cerr); 00509 perr << *p; 00510 perr.endl(); 00511 } 00512 } 00513 00514

Generated on Tue Aug 17 16:00:01 2004 for PLearn by doxygen 1.3.7