#include "yamlgmcfgrd.h" #include "yamlext.h" #include #include #include #include #include namespace genesis { using namespace geoworld; class ConfigValue : public IConfigValue { protected: const YAML::Node _node; mutable IConfigSection * _sect; mutable IConfigSequence * _seq; template< typename T > mars::Range< T > autorange () const { T min, max; if (_node.Type() == YAML::NodeType::Sequence) { _node[0] >> min; _node[1] >> max; } else { _node >> min; _node >> max; } return mars::Range< T > (min, max); } virtual mars::RangeX< double > & toRange (mars::RangeX< double > & out) const; virtual mars::RangeX< long > & toRange (mars::RangeX< long > & out) const; public: ConfigValue( const YAML::Node & nd ); virtual IConfigSection * operator >> (IConfigSection * & pSection) const; virtual IConfigSequence * operator >> (IConfigSequence * & pSequence) const; virtual std::string & operator >> (std::string & out) const; virtual float & operator >> (float & out) const; virtual bool & operator >> (bool & out) const; virtual unsigned int & operator >> (unsigned int & out) const; virtual unsigned short & operator >> (unsigned short & out) const; virtual VectorTag< GeoHeightMap::Precision >::V2 & operator >> (VectorTag< GeoHeightMap::Precision >::V2 & out) const; virtual VectorTag< GeoHeightMap::Precision >::V3 & operator >> (VectorTag< GeoHeightMap::Precision >::V3 & out) const; virtual ~ConfigValue(); }; class ConfigSection : public IConfigSection { private: typedef std::map< std::string, ConfigValue * > Map; mutable Map _map; const YAML::Node _node; public: ConfigSection( const YAML::Node & nd ); virtual const IConfigValue * operator []( const std::string & sKey ) const; virtual ~ConfigSection(); }; class ConfigSequence : public IConfigSequence { private: typedef std::vector< ConfigValue * > List; mutable List _list; const YAML::Node _node; public: ConfigSequence( const YAML::Node & nd ); virtual const IConfigValue * operator []( const size_t & nIdx ) const; virtual ~ConfigSequence(); }; class GMFactory : public IConfigGMFactory { private: ConfigSection _section; public: GMFactory(const std::string & name, const std::string & alias, const YAML::Node & nd, const Settings & settings) : IConfigGMFactory(name, alias, settings), _section(nd) {} virtual IConfigSection * getSection() { return &_section; } }; class GTFactory : public IConfigGTFactory { private: ConfigSection _section; public: GTFactory(const std::string & name, const std::string & alias, const YAML::Node & nd, const Settings & settings) : IConfigGTFactory(name, alias, settings), _section(nd) {} virtual IConfigSection * getSection() { return &_section; } }; YAMLGeoMorphConfigReader::YAMLGeoMorphConfigReader(std::istream & input) : _pList(new FactoryVector()), _docs(YAML::LoadAll(input)), _i(_docs.begin()) {} YAMLGeoMorphConfigReader::~YAMLGeoMorphConfigReader() { for (FactoryVector::iterator i = _pList->begin(); i != _pList->end(); ++i) delete *i; delete _pList; } IConfigFactoryBase * YAMLGeoMorphConfigReader::readNext() { using namespace YAML; Node node = *_i++; if (node.IsNull()) return NULL; if (node.Type() != NodeType::Map) throw GMMalformedConfigEx("Expected map"); // TODO: Proper exception handling std::string sName, sAlias; auto rruj = Dump(node); node["factory"] >> sName; try { node["alias"] >> sAlias; } catch (YAML::TypedKeyNotFound< std::string >) { sAlias = sName; } IConfigFactoryBase * pFactory; try { if (node.Tag() == "!template") pFactory = readGTFactory(sName, sAlias, &node); else if (node.Tag() == "!morph" || node.Tag().empty()) pFactory = readGMFactory(sName, sAlias, &node); else throw GMMalformedConfigEx("Unknown document tag type: " + node.Tag()); } catch (YAML::RepresentationException &) { throw GMMalformedConfigEx("Malformed"); } _pList->push_back(pFactory); return pFactory; } GeoTemplatePhase YAMLGeoMorphConfigReader::getPhaseFor( const std::string & sPhase ) { if (sPhase == "pre") return geoworld::GTP_Pre; else if (sPhase == "post") return geoworld::GTP_Post; else throw InvalidPhaseName(); } geoworld::IConfigGMFactory * YAMLGeoMorphConfigReader::readGMFactory(const std::string & sName, const std::string & sAlias, const YAML::Node * pndConfigSection) { IConfigGMFactory::Settings settings; (*pndConfigSection)["frequency"] >> settings.frequency; return new GMFactory(sName, sAlias, (*pndConfigSection)["parameters"], settings); } geoworld::IConfigGTFactory * YAMLGeoMorphConfigReader::readGTFactory(const std::string & sName, const std::string & sAlias, const YAML::Node * pndConfigSection) { IConfigGTFactory::Settings settings; std::string sPhase; (*pndConfigSection)["phase"] >> sPhase; try { settings.phase = getPhaseFor(sPhase); } catch (InvalidPhaseName &) { throw YAML::InvalidScalar(pndConfigSection->Mark()); } return new GTFactory(sName, sAlias, (*pndConfigSection)["parameters"], settings); } ConfigSection::ConfigSection( const YAML::Node & nd ) : _node(nd) { if (nd.Type() != YAML::NodeType::Map) throw GMMalformedConfigEx("Expected map"); } ConfigSection::~ConfigSection() { for (Map::iterator i = _map.begin(); i != _map.end(); ++i) delete i->second; } const IConfigValue * ConfigSection::operator [] ( const std::string & sKey ) const { ConfigValue * pValue = NULL; if (_map.find(sKey) == _map.end()) { pValue = new ConfigValue(_node[sKey]); _map[sKey] = pValue; } else pValue = _map[sKey]; return pValue; } ConfigSequence::ConfigSequence( const YAML::Node & nd ) : _node(nd) { if (nd.Type() != YAML::NodeType::Sequence) throw GMMalformedConfigEx("Expected sequence"); } ConfigSequence::~ConfigSequence() { for (List::iterator i = _list.begin(); i != _list.end(); ++i) delete *i; } const IConfigValue * ConfigSequence::operator [] ( const size_t & nIdx ) const { ConfigValue * pValue = NULL; if (nIdx >= _list.size()) { _list.resize(nIdx + 1); pValue = new ConfigValue(_node[nIdx]); _list[nIdx] = pValue; } else pValue = _list[nIdx]; return pValue; } std::string & ConfigValue::operator >> ( std::string & out ) const { try { _node >> out; return out; } catch (YAML::TypedKeyNotFound< std::string > & e) { throw GMInvalidPropertyEx(e.key, e.msg.c_str()); } } IConfigSection * ConfigValue::operator >>( IConfigSection * & pSection ) const { if (_sect == NULL) _sect = new ConfigSection(_node); return _sect; } IConfigSequence * ConfigValue::operator>>( IConfigSequence * & pSequence ) const { if (_seq == NULL) _seq = new ConfigSequence(_node); return _seq; } float & ConfigValue::operator >> ( float & out ) const { try { _node >> out; } catch (YAML::TypedKeyNotFound< std::string > & e) { throw GMInvalidPropertyEx(e.key, e.msg.c_str()); } return out; } bool & ConfigValue::operator >> (bool & out) const { try { _node >> out; } catch (YAML::TypedKeyNotFound< std::string > & e) { throw GMInvalidPropertyEx(e.key, e.msg.c_str()); } return out; } unsigned int & ConfigValue::operator >> (unsigned int & out) const { try { _node >> out; } catch (YAML::TypedKeyNotFound< std::string > & e) { throw GMInvalidPropertyEx(e.key, e.msg.c_str()); } return out; } unsigned short & ConfigValue::operator >>( unsigned short & out ) const { try { _node >> out; } catch (YAML::TypedKeyNotFound< std::string > & e) { throw GMInvalidPropertyEx(e.key, e.msg.c_str()); } return out; } VectorTag< GeoHeightMap::Precision >::V2 & ConfigValue::operator >>( VectorTag< GeoHeightMap::Precision >::V2 & out ) const { if (_node.Type() != YAML::NodeType::Sequence) throw GMMalformedConfigEx("Expected a sequence"); return out = VectorTag< GeoHeightMap::Precision >::V2 (_node[0].as(), _node[1].as()); } VectorTag< GeoHeightMap::Precision >::V3 & ConfigValue::operator >>( VectorTag< GeoHeightMap::Precision >::V3 & out ) const { using Numba = GeoHeightMap::Precision; if (_node.Type() != YAML::NodeType::Sequence) throw GMMalformedConfigEx("Expected a sequence"); return out = VectorTag< Numba >::V3 ( _node[0].as(), _node[1].as(), _node[2].as() ); } mars::RangeX< double > & ConfigValue::toRange( mars::RangeX< double > & out ) const { try { return out = autorange< double >(); } catch (YAML::TypedKeyNotFound< int > & e) { throw GMIndexOutOfBoundsEx(e.key, e.msg); } } mars::RangeX< long > & ConfigValue::toRange( mars::RangeX< long > & out ) const { try { return out = autorange< long >(); } catch (YAML::TypedKeyNotFound< int > & e) { throw GMIndexOutOfBoundsEx(e.key, e.msg); } } ConfigValue::ConfigValue( const YAML::Node & nd ) : _node(nd), _sect(NULL), _seq(NULL) {} ConfigValue::~ConfigValue() { delete _sect; delete _seq; } }