options.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2012, Johannes Meyer, TU Darmstadt
00003 // All rights reserved.
00004 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Flight Systems and Automatic Control group,
00013 //       TU Darmstadt, nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //=================================================================================================
00028 
00029 #include <rosmatlab/options.h>
00030 #include <rosmatlab/log.h>
00031 #include <rosmatlab/exception.h>
00032 
00033 #include <mex.h>
00034 
00035 #include <boost/algorithm/string.hpp>
00036 #include <limits>
00037 
00038 namespace rosmatlab {
00039 
00040 template <typename T>
00041 static T getScalar(const mxArray *value)
00042 {
00043   if (value && mxGetNumberOfElements(value) == 1) {
00044     switch(mxGetClassID(value)) {
00045       case mxSINGLE_CLASS:
00046         return *static_cast<float *>(mxGetData(value));
00047       case mxDOUBLE_CLASS:
00048         return *static_cast<double *>(mxGetData(value));
00049       case mxINT8_CLASS:
00050         return *static_cast<int8_T *>(mxGetData(value));
00051       case mxUINT8_CLASS:
00052         return *static_cast<uint8_T *>(mxGetData(value));
00053       case mxINT16_CLASS:
00054         return *static_cast<int16_T *>(mxGetData(value));
00055       case mxUINT16_CLASS:
00056         return *static_cast<uint16_T *>(mxGetData(value));
00057       case mxINT32_CLASS:
00058         return *static_cast<int32_T *>(mxGetData(value));
00059       case mxUINT32_CLASS:
00060         return *static_cast<uint32_T *>(mxGetData(value));
00061       case mxINT64_CLASS:
00062         return *static_cast<int64_T *>(mxGetData(value));
00063       case mxUINT64_CLASS:
00064         return *static_cast<uint64_T *>(mxGetData(value));
00065 
00066       default: break;
00067     }
00068   }
00069 
00070   return std::numeric_limits<T>::quiet_NaN();
00071 }
00072 
00073 bool Options::isScalar(const mxArray *value)
00074 {
00075   return value && mxGetNumberOfElements(value) == 1;
00076 }
00077 
00078 bool Options::isString(const mxArray *value)
00079 {
00080   return value && mxIsChar(value);
00081 }
00082 
00083 std::string Options::getString(const mxArray *value)
00084 {
00085   if (!isString(value)) return std::string();
00086   std::size_t len = mxGetNumberOfElements(value);
00087   char temp[len + 1];
00088   mxGetString(value, temp, sizeof(temp));
00089   return std::string(temp);
00090 }
00091 
00092 bool Options::isDoubleScalar(const mxArray *value)
00093 {
00094   if (!isScalar(value)) return false;
00095 
00096   switch(mxGetClassID(value)) {
00097     case mxSINGLE_CLASS:
00098     case mxDOUBLE_CLASS:
00099       return true;
00100     default: break;
00101   }
00102 
00103   return false;
00104 }
00105 
00106 double Options::getDoubleScalar(const mxArray *value)
00107 {
00108   return getScalar<double>(value);
00109 }
00110 
00111 bool Options::isIntegerScalar(const mxArray *value)
00112 {
00113   if (!isScalar(value)) return false;
00114 
00115   switch(mxGetClassID(value)) {
00116     case mxINT8_CLASS:
00117     case mxUINT8_CLASS:
00118     case mxINT16_CLASS:
00119     case mxUINT16_CLASS:
00120     case mxINT32_CLASS:
00121     case mxUINT32_CLASS:
00122     case mxINT64_CLASS:
00123     case mxUINT64_CLASS:
00124       return true;
00125 
00126     default: break;
00127   }
00128 
00129   return false;
00130 }
00131 
00132 int Options::getIntegerScalar(const mxArray *value)
00133 {
00134   return getScalar<int>(value);
00135 }
00136 
00137 bool Options::isLogicalScalar(const mxArray *value)
00138 {
00139   return value && mxIsLogicalScalar(value);
00140 }
00141 
00142 bool Options::getLogicalScalar(const mxArray *value)
00143 {
00144   if (isLogicalScalar(value)) return mxIsLogicalScalarTrue(value);
00145   if (isIntegerScalar(value)) return getIntegerScalar(value);
00146   if (isDoubleScalar(value))  return getDoubleScalar(value);
00147   return false;
00148 }
00149 
00150 Options::Options()
00151 {
00152 }
00153 
00154 Options::Options(int nrhs, const mxArray *prhs[], bool lowerCaseKeys)
00155 {
00156   init(nrhs, prhs, lowerCaseKeys);
00157 }
00158 
00159 Options::~Options()
00160 {
00161 }
00162 
00163 void Options::init(int nrhs, const mxArray *prhs[], bool lowerCaseKeys)
00164 {
00165   // initialize from struct
00166   if (nrhs == 1 && mxIsStruct(prhs[0])) {
00167     int n = mxGetNumberOfFields(prhs[0]);
00168     for(int i = 0; i < n; ++i) {
00169       std::string key = mxGetFieldNameByNumber(prhs[0], i);
00170       if (lowerCaseKeys) boost::algorithm::to_lower(key);
00171       set(key, mxGetFieldByNumber(prhs[0], 0, i));
00172     }
00173     return;
00174   }
00175 
00176   // initialize from cell
00177   if (nrhs == 1 && mxIsCell(prhs[0])) {
00178     std::vector<const mxArray *> cell(mxGetNumberOfElements(prhs[0]));
00179     for(int i = 0; i < cell.size(); ++i) {
00180       cell[i] = mxGetCell(prhs[0], i);
00181     }
00182     init(cell.size(), cell.data());
00183     return;
00184   }
00185 
00186   // get default option
00187   if (nrhs % 2 != 0) {
00188     set(std::string(), *prhs);
00189     nrhs--; prhs++;
00190   }
00191 
00192   // iterate through key/value pairs
00193   for(; nrhs > 0; nrhs -= 2, prhs += 2) {
00194     if (!isString(prhs[0])) continue;
00195     std::string key = getString(prhs[0]);
00196     if (lowerCaseKeys) boost::algorithm::to_lower(key);
00197     set(key, prhs[1]);
00198   }
00199 }
00200 
00201 void Options::merge(const Options& other)
00202 {
00203   for(ArrayMap::const_iterator it = other.arrays_.begin(); it != other.arrays_.end(); ++it) {
00204 //    mexPrintf("merged array field %s\n", it->first.c_str());
00205     arrays_[it->first] = it->second;
00206     used_.erase(it->first);
00207   }
00208   for(StringMap::const_iterator it = other.strings_.begin(); it != other.strings_.end(); ++it) {
00209 //    mexPrintf("merged string field %s\n", it->first.c_str());
00210     strings_[it->first] = it->second;
00211     used_.erase(it->first);
00212   }
00213   for(DoubleMap::const_iterator it = other.doubles_.begin(); it != other.doubles_.end(); ++it) {
00214 //    mexPrintf("merged double field %s\n", it->first.c_str());
00215     doubles_[it->first] = it->second;
00216     used_.erase(it->first);
00217   }
00218   for(IntegerMap::const_iterator it = other.integers_.begin(); it != other.integers_.end(); ++it) {
00219 //    mexPrintf("merged integer field %s\n", it->first.c_str());
00220     integers_[it->first] = it->second;
00221     used_.erase(it->first);
00222   }
00223   for(BoolMap::const_iterator it = other.bools_.begin(); it != other.bools_.end(); ++it) {
00224 //    mexPrintf("merged bool field %s\n", it->first.c_str());
00225     bools_[it->first] = it->second;
00226     used_.erase(it->first);
00227   }
00228 }
00229 
00230 void Options::clear()
00231 {
00232   arrays_.clear();
00233   strings_.clear();
00234   doubles_.clear();
00235   integers_.clear();
00236   bools_.clear();
00237   used_.clear();
00238 }
00239 
00240 bool Options::hasKey(const std::string& key) const
00241 {
00242   return arrays_.count(key) || strings_.count(key) || doubles_.count(key) || integers_.count(key) || bools_.count(key);
00243 }
00244 
00245 const mxArray *Options::getArray(const std::string &key) const
00246 {
00247   if (arrays_.count(key)) {
00248     used_.insert(key);
00249     return arrays_.at(key);
00250   }
00251   return 0;
00252 }
00253 
00254 const std::string& Options::getString(const std::string& key, const std::string& default_value) const
00255 {
00256   if (strings_.count(key) && strings_.at(key).size()) {
00257     used_.insert(key);
00258     return strings_.at(key).front();
00259   }
00260   return default_value;
00261 }
00262 
00263 const Options::Strings& Options::getStrings(const std::string &key) const
00264 {
00265   if (strings_.count(key)) {
00266     used_.insert(key);
00267     return strings_.at(key);
00268   }
00269 
00270   static const Strings empty;
00271   return empty;
00272 }
00273 
00274 double Options::getDouble(const std::string& key, double default_value) const
00275 {
00276   if (doubles_.count(key) && doubles_.at(key).size()) {
00277     used_.insert(key);
00278     return doubles_.at(key).front();
00279   }
00280   return default_value;
00281 }
00282 
00283 const Options::Doubles& Options::getDoubles(const std::string &key) const
00284 {
00285   if (doubles_.count(key)) {
00286     used_.insert(key);
00287     return doubles_.at(key);
00288   }
00289   static const Doubles empty;
00290   return empty;
00291 }
00292 
00293 int Options::getInteger(const std::string& key, int default_value) const
00294 {
00295   if (integers_.count(key) && integers_.at(key).size()) {
00296     used_.insert(key);
00297     return integers_.at(key).front();
00298   }
00299   if (doubles_.count(key) && doubles_.at(key).size()) {
00300     used_.insert(key);
00301     return doubles_.at(key).front();
00302   }
00303   return default_value;
00304 }
00305 
00306 const Options::Integers& Options::getIntegers(const std::string &key) const
00307 {
00308   if (integers_.count(key)) {
00309     used_.insert(key);
00310     return integers_.at(key);
00311   }
00312   static const Integers empty;
00313   return empty;
00314 }
00315 
00316 bool Options::getBool(const std::string& key, bool default_value) const
00317 {
00318   if (bools_.count(key)   && bools_.at(key).size())   {
00319     used_.insert(key);
00320     return bools_.at(key).front();
00321   }
00322   if (doubles_.count(key) && doubles_.at(key).size()) {
00323     used_.insert(key);
00324     return doubles_.at(key).front();
00325   }
00326   return default_value;
00327 }
00328 
00329 const Options::Bools& Options::getBools(const std::string &key) const
00330 {
00331   if (bools_.count(key)) {
00332     used_.insert(key);
00333     return bools_.at(key);
00334   }
00335 
00336   static const Bools empty;
00337   return empty;
00338 }
00339 
00340 Options &Options::set(const std::string& key, const std::string& value)
00341 {
00342   strings_[key] = Strings(1, value);
00343   return *this;
00344 }
00345 
00346 Options &Options::set(const std::string& key, double value)
00347 {
00348   doubles_[key] = Doubles(1, value);
00349   return *this;
00350 }
00351 
00352 Options &Options::set(const std::string& key, int value)
00353 {
00354   integers_[key] = Integers(1, value);
00355   return *this;
00356 }
00357 
00358 Options &Options::set(const std::string& key, bool value)
00359 {
00360   bools_[key] = Bools(1, value);
00361   return *this;
00362 }
00363 
00364 Options &Options::add(const std::string& key, const std::string& value)
00365 {
00366   strings_[key].push_back(value);
00367   return *this;
00368 }
00369 
00370 Options &Options::add(const std::string& key, double value)
00371 {
00372   doubles_[key].push_back(value);
00373   return *this;
00374 }
00375 
00376 Options &Options::add(const std::string& key, int value)
00377 {
00378   integers_[key].push_back(value);
00379   return *this;
00380 }
00381 
00382 Options &Options::add(const std::string& key, bool value)
00383 {
00384   bools_[key].push_back(value);
00385   return *this;
00386 }
00387 
00388 Options &Options::set(const std::string &key, const mxArray *value)
00389 {
00390   arrays_[key] = value;
00391 
00392   if (isString(value)) {
00393     std::string str = getString(value);
00394     add(key, str);
00395 
00396     if (boost::algorithm::iequals(str, "on"))  add(key, true);
00397     if (boost::algorithm::iequals(str, "off")) add(key, false);
00398   }
00399 
00400   if (isDoubleScalar(value))  add(key, getDoubleScalar(value));
00401   if (isIntegerScalar(value)) add(key, getIntegerScalar(value));
00402   if (isLogicalScalar(value)) add(key, getLogicalScalar(value));
00403 
00404   if (mxIsCell(value)) {
00405     std::size_t n = mxGetNumberOfElements(value);
00406     for(mwIndex i = 0; i < n; ++i) {
00407       set(key, mxGetCell(value, i));
00408     }
00409   }
00410 }
00411 
00412 void Options::warnUnused() const
00413 {
00414   for(StringMap::const_iterator it = strings_.begin(); it != strings_.end(); ++it) {
00415     if (!used_.count(it->first)) ROSMATLAB_PRINTF("WARNING: unused string argument '%s'", it->first.c_str());
00416   }
00417   for(DoubleMap::const_iterator it = doubles_.begin(); it != doubles_.end(); ++it) {
00418     if (!used_.count(it->first)) ROSMATLAB_PRINTF("WARNING: unused double argument '%s'", it->first.c_str());
00419   }
00420   for(IntegerMap::const_iterator it = integers_.begin(); it != integers_.end(); ++it) {
00421     if (!used_.count(it->first)) ROSMATLAB_PRINTF("WARNING: unused integer argument '%s'", it->first.c_str());
00422   }
00423   for(BoolMap::const_iterator it = bools_.begin(); it != bools_.end(); ++it) {
00424     if (!used_.count(it->first)) ROSMATLAB_PRINTF("WARNING: unused logical argument '%s'", it->first.c_str());
00425   }
00426   for(ArrayMap::const_iterator it = arrays_.begin(); it != arrays_.end(); ++it) {
00427     if (!used_.count(it->first)) ROSMATLAB_PRINTF("WARNING: unused argument '%s'", it->first.c_str());
00428   }
00429 }
00430 
00431 void Options::throwOnUnused() const
00432 {
00433   for(StringMap::const_iterator it = strings_.begin(); it != strings_.end(); ++it) {
00434     if (!used_.count(it->first)) throw Exception("unknown string argument '" + it->first + "'");
00435   }
00436   for(DoubleMap::const_iterator it = doubles_.begin(); it != doubles_.end(); ++it) {
00437     if (!used_.count(it->first)) throw Exception("unknown double argument '" + it->first + "'");
00438   }
00439   for(IntegerMap::const_iterator it = integers_.begin(); it != integers_.end(); ++it) {
00440     if (!used_.count(it->first)) throw Exception("unknown integer argument '" + it->first + "'");
00441   }
00442   for(BoolMap::const_iterator it = bools_.begin(); it != bools_.end(); ++it) {
00443     if (!used_.count(it->first)) throw Exception("unknown logical argument '" + it->first + "'");
00444   }
00445   for(ArrayMap::const_iterator it = arrays_.begin(); it != arrays_.end(); ++it) {
00446     if (!used_.count(it->first)) throw Exception("unknown argument '" + it->first + "'");
00447   }
00448 }
00449 
00450 } // namespace rosmatlab


rosmatlab
Author(s): Johannes Meyer
autogenerated on Fri Jul 25 2014 06:08:36