00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef MAPNIK_ENUMERATION_INCLUDED
00024 #define MAPNIK_ENUMERATION_INCLUDED
00025
00026 #include <mapnik/config.hpp>
00027
00028 #include <vector>
00029 #include <bitset>
00030 #include <iostream>
00031 #include <cstdlib>
00032
00033 namespace mapnik {
00034
00035 class illegal_enum_value : public std::exception
00036 {
00037 public:
00038 illegal_enum_value() {}
00039
00040 illegal_enum_value( const std::string & what ) :
00041 what_( what )
00042 {
00043 }
00044 virtual ~illegal_enum_value() throw() {};
00045
00046 virtual const char * what() const throw()
00047 {
00048 return what_.c_str();
00049 }
00050
00051 protected:
00052 std::string what_;
00053 };
00054
00055
00135 template <class ENUM, int THE_MAX>
00136 class MAPNIK_DECL enumeration {
00137 public:
00138 typedef ENUM native_type;
00139 enumeration() {};
00140 enumeration( ENUM v ) : value_(v) {}
00141 enumeration( const enumeration & other ) : value_(other.value_) {}
00142
00144 void operator=(ENUM v)
00145 {
00146 value_ = v;
00147 }
00148
00150 void operator=(const enumeration & other)
00151 {
00152 value_ = other.value_;
00153 }
00154
00156 operator ENUM() const
00157 {
00158 return value_;
00159 }
00160
00161 enum Max
00162 {
00163 MAX = THE_MAX
00164 };
00165 ENUM max() const
00166 {
00167 return THE_MAX;
00168 }
00172 void from_string(const std::string & str)
00173 {
00174 for (unsigned i = 0; i < THE_MAX; ++i)
00175 {
00176 if (str == our_strings_[i])
00177 {
00178 value_ = static_cast<ENUM>(i);
00179 return;
00180 }
00181 }
00182 throw illegal_enum_value(std::string("Illegal enumeration value '") +
00183 str + "' for enum " + our_name_);
00184 }
00185
00190 std::istream & parse(std::istream & is)
00191 {
00192 std::string word;
00193 char c;
00194
00195 while ( is.peek() != std::char_traits< char >::eof())
00196 {
00197 is >> c;
00198 if ( isspace(c) && word.empty() )
00199 {
00200 continue;
00201 }
00202 if ( isalnum(c) || (c == '_') || c == '-' )
00203 {
00204 word += c;
00205 }
00206 else
00207 {
00208 is.unget();
00209 break;
00210 }
00211 }
00212
00213 try
00214 {
00215 from_string( word );
00216 }
00217 catch (const illegal_enum_value &)
00218 {
00219 is.setstate(std::ios::failbit);
00220 }
00221
00222 return is;
00223 }
00224
00226 std::string as_string() const
00227 {
00228 return our_strings_[value_];
00229 }
00230
00232 std::ostream & print(std::ostream & os = std::cerr) const
00233 {
00234 return os << our_strings_[value_];
00235 }
00236
00238 static const char * get_string(unsigned i)
00239 {
00240 return our_strings_[i];
00241 }
00242
00246 static bool verify(const char * filename, unsigned line_no)
00247 {
00248 for (unsigned i = 0; i < THE_MAX; ++i)
00249 {
00250 if (our_strings_[i] == 0 )
00251 {
00252 std::cerr << "### FATAL: Not enough strings for enum "
00253 << our_name_ << " defined in file '" << filename
00254 << "' at line " << line_no << std::endl;
00255 std::exit(1);
00256 }
00257 }
00258 if ( std::string("") != our_strings_[THE_MAX])
00259 {
00260 std::cerr << "### FATAL: The string array for enum " << our_name_
00261 << " defined in file '" << filename << "' at line " << line_no
00262 << " has too many items or is not terminated with an "
00263 << "empty string." << std::endl;
00264 std::exit(1);
00265 }
00266 return true;
00267 }
00268 static const std::string & get_full_qualified_name()
00269 {
00270 return our_name_;
00271 }
00272 static std::string get_name()
00273 {
00274 std::string::size_type idx = our_name_.find_last_of(":");
00275 if ( idx == std::string::npos )
00276 {
00277 return our_name_;
00278 } else {
00279 return our_name_.substr( idx + 1 );
00280 }
00281 }
00282 private:
00283 ENUM value_;
00284 static const char ** our_strings_ ;
00285 static std::string our_name_ ;
00286 static bool our_verified_flag_;
00287 };
00288
00292 template <class ENUM, int THE_MAX>
00293 std::ostream &
00294 operator<<(std::ostream & os, const mapnik::enumeration<ENUM, THE_MAX> & e)
00295 {
00296 e.print( os );
00297 return os;
00298 }
00299
00303 template <class ENUM, int THE_MAX>
00304 std::istream &
00305 operator>>(std::istream & is, mapnik::enumeration<ENUM, THE_MAX> & e)
00306 {
00307 e.parse( is );
00308 return is;
00309 }
00310
00311 }
00312
00316 #define DEFINE_ENUM( name, e) \
00317 typedef mapnik::enumeration<e, e ## _MAX> name;
00318
00322 #define IMPLEMENT_ENUM( name, strings ) \
00323 template <> const char ** name ::our_strings_ = strings; \
00324 template <> std::string name ::our_name_ = #name; \
00325 template <> bool name ::our_verified_flag_( name ::verify(__FILE__, __LINE__));
00326
00327 #endif // MAPNIK_ENUMERATION_INCLUDED