00001 /*!@file Component/ParamMap.C I/O operations for parameter files */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Component/ParamMap.C $ 00035 // $Id: ParamMap.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #ifndef PARAMMAP_C_DEFINED 00039 #define PARAMMAP_C_DEFINED 00040 00041 #include "Component/ParamMap.H" 00042 00043 #include "Util/Assert.H" 00044 #include "Util/Types.H" 00045 #include "Util/log.H" 00046 00047 #include <fstream> 00048 #include <iomanip> 00049 #include <iostream> 00050 #include <limits> 00051 #include <map> 00052 #include <sstream> 00053 #include <string> 00054 #include <vector> 00055 00056 // ###################################################################### 00057 namespace dummy_namespace_to_avoid_gcc411_bug_ParamMap_C 00058 { 00059 void escapeWrite(std::ostream& ostrm, const std::string& s) 00060 { 00061 for (uint i = 0; i < s.size(); ++i) 00062 { 00063 switch (s[i]) 00064 { 00065 // Need to escape whitespace in order to allow interior 00066 // whitespace within attribute values: 00067 case ' ' : ostrm << '\\' << ' '; break; 00068 case '\t' : ostrm << '\\' << '\t'; break; 00069 case '\n' : ostrm << '\\' << '\n'; break; 00070 00071 // Must escape a backslash itself in order to not confuse it with 00072 // "backslash-as-escape-character" 00073 case '\\' : ostrm << '\\' << '\\'; break; 00074 00075 // Anything else can be written literally 00076 default : ostrm << s[i]; break; 00077 } 00078 } 00079 } 00080 00081 std::string escapeRead(std::istream& istrm) 00082 { 00083 // Read into a std::vector<char> rather than a std::string since it has 00084 // amortized-constant push_back(), which is not necessarily the case 00085 // for std::string. 00086 std::vector<char> buf; 00087 00088 bool finished = false; 00089 00090 // Skip over any unescaped whitespace that precedes the text of interest: 00091 istrm >> std::ws; 00092 00093 while (!finished) 00094 { 00095 const int c = char(istrm.get()); 00096 00097 switch(c) 00098 { 00099 // (1) In case of unescaped whitespace or EOF, we're done: 00100 case EOF: 00101 case ' ': 00102 case '\t': 00103 case '\n': 00104 finished = true; 00105 break; 00106 00107 // (2) In case of a backslash, take the subsequent character literally: 00108 case '\\': 00109 if (istrm.peek() == EOF) 00110 { 00111 // We'd better not find EOF following a backslash 00112 LFATAL("Incomplete escape sequence before EOF!"); 00113 } 00114 buf.push_back(char(istrm.get())); 00115 break; 00116 00117 // (3) Otherwise, take the current character literally: 00118 default: 00119 buf.push_back(char(c)); 00120 break; 00121 } 00122 } 00123 00124 // Must add a null-terminator 00125 buf.push_back('\0'); 00126 00127 // Gobble up any trailing un-escaped whitespace from the input stream 00128 while( istrm.peek() == '\t' || istrm.peek() == ' ' ) 00129 istrm.get(); 00130 00131 return std::string(&buf[0]); 00132 } 00133 00134 struct Param 00135 { 00136 Param() : str(), pmap() {} 00137 00138 Param(double v) : str(), pmap() 00139 { 00140 std::ostringstream oss; 00141 oss << std::setprecision(25) << v; 00142 str = oss.str(); 00143 } 00144 00145 Param(int v) : str(), pmap() 00146 { 00147 std::ostringstream oss; oss << v; str = oss.str(); 00148 } 00149 00150 Param(const std::string& s) : str(s), pmap() {} 00151 00152 Param(const rutz::shared_ptr<ParamMap>& p) : str(), pmap(p) {} 00153 00154 void put(std::ostream& ostrm, int indentlev = 0) const 00155 { 00156 if (pmap.get() != 0) 00157 { 00158 ostrm << "{\n"; 00159 pmap->format(ostrm, indentlev+1); 00160 for (int i = 0; i < indentlev; ++i) ostrm << '\t'; 00161 ostrm << '}'; 00162 } 00163 else 00164 { 00165 escapeWrite(ostrm, str); 00166 } 00167 } 00168 00169 double getDouble() const 00170 { 00171 std::istringstream iss(str); 00172 double val; 00173 iss >> val; 00174 return val; 00175 } 00176 00177 int getInt() const 00178 { 00179 std::istringstream iss(str); 00180 int val; 00181 iss >> val; 00182 return val; 00183 } 00184 00185 rutz::shared_ptr<ParamMap> getMap() const 00186 { 00187 if (pmap.get() == 0) 00188 { 00189 LFATAL("No such parameter submap."); 00190 } 00191 return pmap; 00192 } 00193 00194 bool isLeaf() const 00195 { 00196 if (pmap.get() == 0) 00197 return true; 00198 else 00199 return false; 00200 } 00201 00202 std::string str; 00203 mutable rutz::shared_ptr<ParamMap> pmap; 00204 }; 00205 } 00206 00207 using namespace dummy_namespace_to_avoid_gcc411_bug_ParamMap_C; 00208 00209 // ###################################################################### 00210 struct ParamMap::Impl 00211 { 00212 typedef std::map<std::string, Param> MapType; 00213 00214 MapType itsParams; 00215 }; 00216 00217 // ###################################################################### 00218 struct ParamMap::key_iterator::IterRep 00219 { 00220 ParamMap::Impl::MapType::const_iterator iter; 00221 }; 00222 00223 // ###################################################################### 00224 ParamMap::key_iterator::key_iterator() : 00225 rep(new IterRep) 00226 {} 00227 00228 // ###################################################################### 00229 ParamMap::key_iterator::~key_iterator() 00230 { 00231 delete rep; 00232 } 00233 00234 // ###################################################################### 00235 ParamMap::key_iterator::key_iterator(const key_iterator& other) : 00236 rep(new IterRep) 00237 { 00238 rep->iter = other.rep->iter; 00239 } 00240 00241 // ###################################################################### 00242 ParamMap::key_iterator& 00243 ParamMap::key_iterator::operator=(const key_iterator& other) 00244 { 00245 rep->iter = other.rep->iter; return *this; 00246 } 00247 00248 // ###################################################################### 00249 const std::string& ParamMap::key_iterator::operator*() const 00250 { 00251 return (*(rep->iter)).first; 00252 } 00253 00254 // ###################################################################### 00255 ParamMap::key_iterator& 00256 ParamMap::key_iterator::operator++() 00257 { 00258 ++(rep->iter); return *this; 00259 } 00260 00261 // ###################################################################### 00262 bool ParamMap::key_iterator::operator==(const key_iterator& other) const 00263 { 00264 return rep->iter == other.rep->iter; 00265 } 00266 00267 // ###################################################################### 00268 bool ParamMap::key_iterator::operator!=(const key_iterator& other) const 00269 { 00270 return rep->iter != other.rep->iter; 00271 } 00272 00273 // ###################################################################### 00274 rutz::shared_ptr<ParamMap> ParamMap::loadPmapFile(const std::string& fname) 00275 { 00276 rutz::shared_ptr<ParamMap> result(new ParamMap); 00277 result->load(fname); 00278 return result; 00279 } 00280 00281 // ###################################################################### 00282 rutz::shared_ptr<ParamMap> ParamMap::loadConfFile(const std::string& fname) 00283 { 00284 rutz::shared_ptr<ParamMap> pmap(new ParamMap); 00285 00286 std::ifstream inFile(fname.c_str()); 00287 00288 int counter = 0; 00289 bool inComment = false; 00290 std::string instring; 00291 std::string paramName; 00292 while (inFile >> instring) 00293 { 00294 if (instring == "#") 00295 { 00296 // the comment code "#" toggles our in-comment state 00297 inComment = !inComment; 00298 } 00299 else if (!inComment) //real line found 00300 { 00301 if (paramName.length() == 0) 00302 { 00303 paramName.swap(instring); 00304 } 00305 else 00306 { 00307 pmap->putStringParam(paramName, instring); 00308 LINFO("%s[%d]: %s = %s", 00309 fname.c_str(), counter, 00310 paramName.c_str(), instring.c_str()); 00311 paramName.clear(); 00312 ++counter; 00313 } 00314 } 00315 } 00316 00317 return pmap; 00318 } 00319 00320 /* 00321 // ###################################################################### 00322 template <class T> 00323 rutz::shared_ptr<ParamMap> ParamMap::loadC_Map(const std::map <std::string, T> c_map) 00324 { 00325 typedef std::map<std::string, T> TMap; 00326 rutz::shared_ptr<ParamMap> pmap(new ParamMap); 00327 00328 int counter = 0; 00329 T val; 00330 std::string str, paramName; 00331 TMap::iterator i; 00332 for(i = c_map.begin(); i != c_map.end(); ++i) 00333 { 00334 paramName = i->first; 00335 val = i->second; 00336 std::ostringstream oss; oss << val; str = oss.str(); 00337 pmap->putStringParam(paramName, str); 00338 LINFO("cmap:[%d]: %s = %s", 00339 counter, paramName.c_str(), str.c_str()); 00340 paramName.clear(); 00341 ++counter; 00342 } 00343 return pmap; 00344 } 00345 */ 00346 // ###################################################################### 00347 ParamMap::ParamMap() : 00348 rep(new Impl) 00349 {} 00350 00351 // ###################################################################### 00352 ParamMap::ParamMap(const std::string& fname) : 00353 rep(new Impl) 00354 { 00355 load(fname); 00356 } 00357 00358 // ###################################################################### 00359 ParamMap::~ParamMap() 00360 { 00361 delete rep; 00362 } 00363 00364 // ###################################################################### 00365 ParamMap::key_iterator 00366 ParamMap::keys_begin() const 00367 { 00368 key_iterator result; 00369 result.rep->iter = rep->itsParams.begin(); 00370 return result; 00371 } 00372 00373 // ###################################################################### 00374 ParamMap::key_iterator 00375 ParamMap::keys_end() const 00376 { 00377 key_iterator result; 00378 result.rep->iter = rep->itsParams.end(); 00379 return result; 00380 } 00381 00382 // ###################################################################### 00383 void ParamMap::load(std::istream& istrm) 00384 { 00385 while (istrm.peek() != EOF) 00386 { 00387 if (istrm.peek() == '#') 00388 { 00389 istrm.ignore(std::numeric_limits<int>::max(), '\n'); 00390 istrm >> std::ws; 00391 continue; 00392 } 00393 00394 const std::string attribname = escapeRead(istrm); 00395 00396 if (istrm.peek() != '{') 00397 { 00398 std::string attribval; 00399 while( istrm.peek() == '\t' || istrm.peek() == ' ' ) 00400 istrm.get(); 00401 if ( istrm.peek() == '\n' ) 00402 attribval = ""; 00403 else 00404 attribval = escapeRead(istrm); 00405 00406 rep->itsParams.insert(Impl::MapType::value_type(attribname, 00407 attribval)); 00408 } 00409 else 00410 { 00411 std::string attribval; 00412 00413 int bracelevel = 0; 00414 // First time through loop we pick up the opening brace '{' 00415 do 00416 { 00417 int c = istrm.get(); 00418 00419 if (c == EOF) 00420 { 00421 LFATAL("Unexpected EOF before closing brace '}'."); 00422 } 00423 switch (c) 00424 { 00425 case '{': 00426 // Don't add the opening brace to the value string 00427 if (bracelevel++ > 0) 00428 attribval.push_back(char(c)); 00429 break; 00430 case '}': 00431 // Don't add the closing brace to the value string 00432 if (--bracelevel > 0) 00433 attribval.push_back(char(c)); 00434 break; 00435 default: 00436 attribval.push_back(char(c)); 00437 break; 00438 } 00439 } 00440 while (bracelevel > 0); 00441 00442 rutz::shared_ptr<ParamMap> submap(new ParamMap); 00443 00444 std::istringstream iss(attribval); 00445 submap->load(iss); 00446 00447 rep->itsParams.insert(Impl::MapType::value_type(attribname, submap)); 00448 } 00449 00450 istrm >> std::ws; 00451 } 00452 } 00453 00454 // ###################################################################### 00455 void ParamMap::load(const std::string& fname) 00456 { 00457 std::ifstream ifs(fname.c_str()); 00458 00459 if (!ifs.is_open()) 00460 { 00461 LFATAL("Couldn't open file '%s' for reading.", fname.c_str()); 00462 } 00463 00464 load(ifs); 00465 00466 ifs.close(); 00467 } 00468 00469 // ###################################################################### 00470 void ParamMap::format(std::ostream& ostrm, int indentlev) const 00471 { 00472 for (Impl::MapType::const_iterator 00473 itr = rep->itsParams.begin(), stop = rep->itsParams.end(); 00474 itr != stop; 00475 ++itr) 00476 { 00477 for (int i = 0; i < indentlev; ++i) ostrm << '\t'; 00478 escapeWrite(ostrm, (*itr).first); 00479 ostrm << " "; 00480 (*itr).second.put(ostrm, indentlev); 00481 ostrm << '\n'; 00482 } 00483 } 00484 00485 // ###################################################################### 00486 void ParamMap::format(const std::string& fname) const 00487 { 00488 std::ofstream ofs(fname.c_str()); 00489 00490 if (!ofs.is_open()) 00491 { 00492 LFATAL("Couldn't open file '%s' for writing.", fname.c_str()); 00493 } 00494 00495 format(ofs); 00496 00497 ofs.close(); 00498 } 00499 00500 // ###################################################################### 00501 bool ParamMap::hasParam(const std::string& paramname) const 00502 { 00503 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00504 return (itr != rep->itsParams.end()); 00505 } 00506 00507 // ###################################################################### 00508 bool ParamMap::isLeaf(const std::string& paramname) const 00509 { 00510 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00511 if (itr->second.isLeaf()) 00512 return true; 00513 else 00514 return false; 00515 } 00516 00517 // ###################################################################### 00518 uint ParamMap::getsize() const 00519 { 00520 return rep->itsParams.size(); 00521 } 00522 00523 // ###################################################################### 00524 rutz::shared_ptr<ParamMap> ParamMap::getSubpmap(const std::string& paramname) const 00525 { 00526 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00527 if (itr == rep->itsParams.end()) 00528 { 00529 LFATAL("No parameter named '%s'.", paramname.c_str()); 00530 } 00531 return (*itr).second.getMap(); 00532 } 00533 00534 // ###################################################################### 00535 std::string ParamMap::getStringParam(const std::string& paramname) const 00536 { 00537 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00538 if (itr == rep->itsParams.end()) 00539 { 00540 LFATAL("No parameter named '%s'.", paramname.c_str()); 00541 } 00542 return (*itr).second.str; 00543 } 00544 00545 // ###################################################################### 00546 double ParamMap::getDoubleParam(const std::string& paramname) const 00547 { 00548 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00549 if (itr == rep->itsParams.end()) 00550 { 00551 LFATAL("No parameter named '%s'.", paramname.c_str()); 00552 } 00553 return (*itr).second.getDouble(); 00554 } 00555 00556 // ###################################################################### 00557 int ParamMap::getIntParam(const std::string& paramname) const 00558 { 00559 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00560 if (itr == rep->itsParams.end()) 00561 { 00562 LFATAL("No parameter named '%s'.", paramname.c_str()); 00563 } 00564 return (*itr).second.getInt(); 00565 } 00566 00567 // ###################################################################### 00568 std::string ParamMap::getStringParam(const std::string& paramname, 00569 const std::string& defval) const 00570 { 00571 std::string result = defval; 00572 queryStringParam(paramname, result); 00573 return result; 00574 } 00575 00576 // ###################################################################### 00577 double ParamMap::getDoubleParam(const std::string& paramname, 00578 const double defval) const 00579 { 00580 double result = defval; 00581 queryDoubleParam(paramname, result); 00582 return result; 00583 } 00584 00585 // ###################################################################### 00586 int ParamMap::getIntParam(const std::string& paramname, 00587 const int defval) const 00588 { 00589 int result = defval; 00590 queryIntParam(paramname, result); 00591 return result; 00592 } 00593 00594 // ###################################################################### 00595 rutz::shared_ptr<ParamMap> ParamMap::lookupSubpmap(const std::string& paramname) 00596 { 00597 if (hasParam(paramname)) 00598 return getSubpmap(paramname); 00599 00600 // else... 00601 rutz::shared_ptr<ParamMap> submap(new ParamMap); 00602 putSubpmap(paramname, submap); 00603 return submap; 00604 } 00605 00606 // ###################################################################### 00607 ParamMap::ReturnCode 00608 ParamMap::queryStringParam(const std::string& paramname, std::string& result) const 00609 { 00610 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00611 if (itr != rep->itsParams.end()) 00612 { 00613 const std::string new_val = (*itr).second.str; 00614 if (result.compare(new_val) != 0) 00615 { 00616 result = new_val; 00617 return CHANGED; 00618 } 00619 else 00620 return UNCHANGED; 00621 } 00622 00623 // else... 00624 LINFO("Parameter '%s' not found; using default value '%s'.", 00625 paramname.c_str(), result.c_str()); 00626 return MISSING; 00627 } 00628 00629 // ###################################################################### 00630 ParamMap::ReturnCode 00631 ParamMap::queryDoubleParam(const std::string& paramname, double& result) const 00632 { 00633 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00634 if (itr != rep->itsParams.end()) 00635 { 00636 const double new_val = (*itr).second.getDouble(); 00637 if (new_val != result) 00638 { 00639 result = new_val; 00640 return CHANGED; 00641 } 00642 else 00643 return UNCHANGED; 00644 } 00645 00646 // else... 00647 LINFO("Parameter '%s' not found; using default value '%f'.", 00648 paramname.c_str(), result); 00649 return MISSING; 00650 } 00651 00652 // ###################################################################### 00653 ParamMap::ReturnCode 00654 ParamMap::queryIntParam(const std::string& paramname, int& result) const 00655 { 00656 Impl::MapType::const_iterator itr = rep->itsParams.find(paramname); 00657 if (itr != rep->itsParams.end()) 00658 { 00659 const int new_val = (*itr).second.getInt(); 00660 if (new_val != result) 00661 { 00662 result = new_val; 00663 return CHANGED; 00664 } 00665 else 00666 return UNCHANGED; 00667 } 00668 00669 // else... 00670 LINFO("Parameter '%s' not found; using default value '%d'.", 00671 paramname.c_str(), result); 00672 return MISSING; 00673 } 00674 00675 // ###################################################################### 00676 void ParamMap::putSubpmap(const std::string& paramname, const rutz::shared_ptr<ParamMap>& val) 00677 { 00678 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00679 } 00680 00681 // ###################################################################### 00682 void ParamMap::putStringParam(const std::string& paramname, const std::string& val) 00683 { 00684 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00685 } 00686 00687 // ###################################################################### 00688 void ParamMap::putDoubleParam(const std::string& paramname, double val) 00689 { 00690 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00691 } 00692 00693 // ###################################################################### 00694 void ParamMap::putIntParam(const std::string& paramname, int val) 00695 { 00696 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00697 } 00698 00699 // ###################################################################### 00700 void ParamMap::replaceSubpmap(const std::string& paramname, 00701 const rutz::shared_ptr<ParamMap>& val) 00702 { 00703 rep->itsParams.erase(rep->itsParams.find(paramname)); 00704 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00705 } 00706 00707 // ###################################################################### 00708 void ParamMap::replaceStringParam(const std::string& paramname, const std::string& val) 00709 { 00710 rep->itsParams.erase(rep->itsParams.find(paramname)); 00711 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00712 } 00713 00714 // ###################################################################### 00715 void ParamMap::replaceDoubleParam(const std::string& paramname, double val) 00716 { 00717 rep->itsParams.erase(rep->itsParams.find(paramname)); 00718 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00719 } 00720 00721 // ###################################################################### 00722 void ParamMap::replaceIntParam(const std::string& paramname, int val) 00723 { 00724 rep->itsParams.erase(rep->itsParams.find(paramname)); 00725 rep->itsParams.insert(Impl::MapType::value_type(paramname, val)); 00726 } 00727 00728 // ###################################################################### 00729 void ParamMap::clear() 00730 { 00731 rep->itsParams.clear(); 00732 } 00733 00734 // ###################################################################### 00735 void ParamMap::erase(const std::string& paramname) 00736 { 00737 // should have error handling 00738 rep->itsParams.erase(rep->itsParams.find(paramname)); 00739 } 00740 00741 // ###################################################################### 00742 void ParamMap::print(const std::string& name) const 00743 { 00744 std::cout << "--- begin " << name << " ---\n"; 00745 for (Impl::MapType::const_iterator 00746 itr = rep->itsParams.begin(), stop = rep->itsParams.end(); 00747 itr != stop; 00748 ++itr) 00749 { 00750 std::cout << "name: " << (*itr).first <<"****" <<std::endl; 00751 std::cout << "val: " << (*itr).second.str <<"****"<< std::endl; 00752 } 00753 std::cout << "--- end " << name << " ---\n"; 00754 } 00755 00756 // ###################################################################### 00757 /* So things look consistent in everyone's emacs... */ 00758 /* Local Variables: */ 00759 /* indent-tabs-mode: nil */ 00760 /* End: */ 00761 00762 #endif // !PARAMMAP_C_DEFINED