• Main Page
  • Related Pages
  • Classes
  • Files
  • File List

src/LexicalMap.hh

00001 /*
00002  * Copyright Staffan Gimåker 2009-2010.
00003  *
00004  * ---
00005  *
00006  * This file is part of peekabot.
00007  *
00008  * peekabot is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * peekabot is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 #ifndef PEEKABOT_LEXICAL_MAP_HH_INCLUDED
00023 #define PEEKABOT_LEXICAL_MAP_HH_INCLUDED
00024 
00025 
00026 #include "Types.hh"
00027 
00028 #include <map>
00029 #include <string>
00030 #include <vector>
00031 #include <set>
00032 #include <list>
00033 #include <stdexcept>
00034 #include <boost/lexical_cast.hpp>
00035 #include <boost/algorithm/string/trim.hpp>
00036 #include <boost/algorithm/string/split.hpp>
00037 #include <boost/algorithm/string/classification.hpp>
00038 #include <boost/filesystem/path.hpp>
00039 
00040 
00041 namespace peekabot
00042 {
00043     namespace detail
00044     {
00045         template<class S, class T>
00046         inline void lexical_assign(S &lhs, const T &rhs)
00047         {
00048             lhs = boost::lexical_cast<S>(rhs);
00049         }
00050 
00051         template<>
00052         inline void lexical_assign(bool &lhs, const std::string &rhs)
00053         {
00054             if( rhs == "true" || rhs == "on" ||
00055                 rhs == "enable" || rhs == "1" )
00056                 lhs = true;
00057             else if( rhs == "false" || rhs == "off" ||
00058                      rhs == "disable" || rhs == "0" )
00059                 lhs = false;
00060             else
00061                 throw boost::bad_lexical_cast();
00062         }
00063 
00064         template<class T>
00065         inline void lexical_assign(std::list<T> &lhs, const std::string &rhs)
00066         {
00067             lhs.clear();
00068 
00069             std::vector<std::string> components;
00070             boost::split( components, rhs, boost::is_any_of(",") );
00071 
00072             for( size_t i = 0; i < components.size(); ++i )
00073             {
00074                 boost::trim(components[i]);
00075                 if( !components[i].empty() )
00076                 {
00077                     T tmp;
00078                     lexical_assign(tmp, components[i]);
00079                     lhs.push_back(tmp);
00080                 }
00081             }
00082         }
00083 
00084         template<class T>
00085         inline void lexical_assign(std::string &lhs, const std::list<T> &rhs)
00086         {
00087             lhs = "";
00088             for( typename std::list<T>::const_iterator it = rhs.begin();
00089                  it != rhs.end(); ++it )
00090             {
00091                 std::string tmp;
00092                 lexical_assign(tmp, *it);
00093                 if( it != rhs.begin() )
00094                     lhs += ", ";
00095                 lhs += tmp;
00096             }
00097         }
00098 
00099         // boost::lexical_cast<path>() doesn't work if the input string
00100         // contains spaces
00101         template<> inline void lexical_assign(
00102             boost::filesystem::path &lhs, const std::string &rhs)
00103         {
00104             lhs = rhs;
00105         }
00106 
00107         template<> inline void lexical_assign(
00108             RGBColor &lhs, const std::string &rhs)
00109         {
00110             std::vector<std::string> components;
00111             boost::split( components, rhs, boost::is_any_of(",") );
00112 
00113             if( components.size() != 3 )
00114                 throw std::runtime_error(
00115                     "Colors must be in the format R,G,B, "
00116                     "where 0 <= R,G,B <= 1");
00117 
00118             for( std::size_t i = 0; i < 3; ++i )
00119                 boost::trim(components[i]);
00120 
00121             float r = boost::lexical_cast<float>(components[0]);
00122             float g = boost::lexical_cast<float>(components[1]);
00123             float b = boost::lexical_cast<float>(components[2]);
00124 
00125             if( r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1 )
00126                 throw std::runtime_error(
00127                     "Colors must be in the format R,G,B, "
00128                     "where 0 <= R,G,B <= 1");
00129 
00130             lhs = RGBColor(r, g, b);
00131         }
00132     }
00133 
00134     class LexicalMap
00135     {
00136         typedef std::map<std::string, std::string> OptionMap;
00137 
00138     public:
00139         typedef std::string KeyType;
00140 
00141         const std::string &get_raw(const KeyType &key) const
00142         {
00143             OptionMap::const_iterator it = m_options.find(key);
00144             if( it == m_options.end() )
00145                 throw std::runtime_error("Key '" + key + "' not found");
00146             return it->second;
00147         }
00148 
00149         template<typename T>
00150         T get(const KeyType &key) const
00151         {
00152             const std::string &val = get_raw(key);
00153             try
00154             {
00155                 T ret;
00156                 detail::lexical_assign(ret, val);
00157                 return ret;
00158             }
00159             catch(...)
00160             {
00161                 throw std::runtime_error(
00162                     "Malformed value '" + val +
00163                     "' for key '" + key + "'");
00164             }
00165         }
00166 
00167         inline void set_raw(const KeyType &key, const std::string &val)
00168         {
00169             m_options[key] = val;
00170         }
00171 
00172         template<typename T>
00173         void set(const KeyType &key, const T &val)
00174         {
00175             std::string raw;
00176             detail::lexical_assign(raw, val);
00177             set_raw(key, raw);
00178         }
00179 
00180         inline void erase(const KeyType &key)
00181         {
00182             m_options.erase(key);
00183         }
00184 
00185         inline void clear()
00186         {
00187             m_options.clear();
00188         }
00189 
00190         inline std::size_t count(const KeyType &key) const
00191         {
00192             return m_options.count(key);
00193         }
00194 
00195         template<typename T>
00196         bool has_type(const KeyType &key) const
00197         {
00198             if( !count(key) )
00199             {
00200                 throw std::runtime_error("Key '" + key + "' not found");
00201             }
00202             else
00203             {
00204                 try
00205                 {
00206                     T tmp;
00207                     detail::lexical_assign(tmp, get_raw(key));
00208                     return true;
00209                 }
00210                 catch(...)
00211                 {
00212                     return false;
00213                 }
00214             }
00215         }
00216 
00217         typedef OptionMap::const_iterator const_iterator;
00218 
00219         inline const_iterator begin() const
00220         {
00221             return m_options.begin();
00222         }
00223 
00224         inline const_iterator end() const
00225         {
00226             return m_options.end();
00227         }
00228 
00229     protected:
00230         OptionMap m_options;
00231     };
00232 }
00233 
00234 
00235 #endif // PEEKABOT_LEXICAL_MAP_HH_INCLUDED

Generated on Sun Jan 30 2011 for peekabot by  doxygen 1.7.1