#include "yamlminreader.h" #include "yamlext.h" #include #include #include #include namespace genesis { using namespace geoworld; static void operator >> (const YAML::Node & nd, geoworld::PointScale & pt) { unsigned value = static_cast (pt); nd >> value; pt = static_cast (value); } static void operator >> (const YAML::Node & nd, geoworld::MineralPtr & mineral) { std::string id; nd >> id; mineral = id; } static void operator >> (const YAML::Node & nd, geoworld::MinClassPtr & rock) { std::string id; nd >> id; rock = id; } inline static void operator >> (const YAML::Node & nd, geoworld::PhasePoint & pp) { nd[0] >> pp.temperature; nd[1] >> pp.pressure; } class MineralsYAMLReaderImpl { private: geoworld::PetrogenyDef * _defPetroDef; std::istream & _input; public: template void readScalarOrSequence (const YAML::Node & nd, void(MineralsYAMLReaderImpl::*fnProc)(const YAML::Node &, T &), std::list & collection); template void readScalarOrSequence (const YAML::Node & nd, void(MineralsYAMLReaderImpl::*fnProc)(const YAML::Node &, T &), std::vector & collection); template void readScalarOrSequenceA (const YAML::Node & nd, void(MineralsYAMLReaderImpl::*fnProc)(const YAML::Node &, T &), L & collection); template void readScalarOrBitset (const YAML::Node & nd, void(MineralsYAMLReaderImpl::*fnProc)(const YAML::Node &, T &), std::bitset & bset); void readGroupDef( IMineralsDatabase * pMinDB, const YAML::Node & nd, mars::ptr & group ); void readClassDefinition ( const YAML::Node & nd, mars::ptr & rclass); void readMineralDef( const YAML::Node &nd, mars::ptr & mineral ); void readClassDisposition( const YAML::Node &nd, geoworld::MineralClass::Disposition & disposition ); void readYield (const YAML::Node & nd, geoworld::MineralDef::YieldSet & set); void readGenesis (const YAML::Node & nd, geoworld::PetrogenyDef & mineral); void readEnvironment (const YAML::Node & nd, geoworld::MinClassPtr & clazz); void readAssociation (const YAML::Node & nd, geoworld::MineralReference & assoc); void readDistribution (const YAML::Node & nd, geoworld::DepositDistribution & distribution); void readSediment (const YAML::Node & nd, geoworld::Sediment & sediment); void resolveReferences (); void resolve( geoworld::MineralPtr & rWRef ); template static void strToEnumV (const std::string & str, E & enRet, const char * szKey, va_list & vl); template static void strToEnumOrPtSc (const YAML::Node & nd, E & enRet, geoworld::PointScale & ptsc, const char * szFirst, ...); template static void strToEnum (const YAML::Node & nd, E & enRet, const char * szFirst, ...); template static void strToEnum (const std::string & str, E & enRet, const char * szFirst, ...); MineralsYAMLReaderImpl(std::istream & input); virtual bool load (IMineralsDatabase * pMinDB); }; MineralsYAMLReaderImpl::MineralsYAMLReaderImpl(std::istream & input) : _input(input) {} template void MineralsYAMLReaderImpl::strToEnum( const std::string & str, E & enRet, const char * szFirst, ... ) { va_list vl; va_start(vl, enRet); strToEnumV(str, enRet, szFirst, vl); va_end(vl); } template void MineralsYAMLReaderImpl::strToEnum( const YAML::Node & nd, E & enRet, const char * szFirst, ... ) { std::string sKey; va_list vl; nd >> sKey; va_start(vl, szFirst); strToEnumV(sKey, enRet, szFirst, vl); va_end(vl); } template void MineralsYAMLReaderImpl::strToEnumOrPtSc( const YAML::Node & nd, E & enRet, geoworld::PointScale & ptsc, const char * szFirst, ... ) { std::string sKey; va_list vl; int i; nd >> sKey; i = atoi(sKey.c_str()); if (i > 0 || sKey == "0") ptsc = static_cast (i); else { va_start(vl, szFirst); strToEnumV(sKey, enRet, szFirst, vl); va_end(vl); } } template void MineralsYAMLReaderImpl::strToEnumV( const std::string & str, E & enRet, const char * szKey, va_list & vl ) { while (szKey != NULL) { const E enVal = static_cast< E > (va_arg(vl, int)); if (str == szKey) enRet = enVal; szKey = va_arg(vl, const char *); } } template void MineralsYAMLReaderImpl::readScalarOrBitset( const YAML::Node & nd, void(MineralsYAMLReaderImpl::* fnProc)(const YAML::Node &, T &), std::bitset & bset ) { using namespace YAML; if (nd.Type() == NodeType::Sequence) { for (const_iterator it = nd.begin(); it != nd.end(); ++it) { T data; (this->*fnProc)(*it, data); if (data > 0 && data < N) bset.set(data); } } else { T data; (this->*fnProc)(nd, data); if (data > 0 && data < N) bset.set(data); } } template void MineralsYAMLReaderImpl::readScalarOrSequenceA( const YAML::Node & nd, void(MineralsYAMLReaderImpl::* fnProc)(const YAML::Node &, T &), L & collection ) { using namespace YAML; if (nd.Type() == NodeType::Sequence) { for (const_iterator it = nd.begin(); it != nd.end(); ++it) { T data; (this->*fnProc)(*it, data); collection.push_back(data); } } else { T data; (this->*fnProc)(nd, data); collection.push_back(data); } } template void MineralsYAMLReaderImpl::readScalarOrSequence( const YAML::Node & nd, void(MineralsYAMLReaderImpl::* fnProc)(const YAML::Node &, T &), std::vector & collection ) { readScalarOrSequenceA >(nd, fnProc, collection); } template void MineralsYAMLReaderImpl::readScalarOrSequence( const YAML::Node & nd, void(MineralsYAMLReaderImpl::* fnProc)(const YAML::Node &, T &), std::list & collection ) { readScalarOrSequenceA >(nd, fnProc, collection); } void MineralsYAMLReaderImpl::readYield (const YAML::Node & nd, MineralDef::YieldSet & set) { using namespace YAML; for (const_iterator itchem = nd.begin(); itchem != nd.end(); ++itchem) { std::string smin; const Node & ndParticle = itchem->second; float pct, flux = 0.0f; if (ndParticle.Type() == NodeType::Scalar) ndParticle >> pct; else { ndParticle[0] >> pct; ndParticle[1] >> flux; } itchem->first >> smin; set.add (MineralDef::YieldMin (smin, pct, flux)); } } void MineralsYAMLReaderImpl::readClassDefinition ( const YAML::Node & nd, mars::ptr & rclass) { using namespace YAML; for (const_iterator it = nd.begin(); it != nd.end(); ++it) { std::string key; it->first >> key; if (key == "class") { it->second >> rclass->name; } else if (key == "type") { strToEnum(it->second, rclass->type, "igneous", MineralClass::Type_Igneous, "sedimentary", MineralClass::Type_Sedimentary, NULL ); } else if (key == "dispositions") { readScalarOrSequence (it->second, &MineralsYAMLReaderImpl::readClassDisposition, rclass->dispositions); } } } void MineralsYAMLReaderImpl::readGenesis( const YAML::Node & nd, PetrogenyDef & genesis ) { using namespace YAML; genesis = *this->_defPetroDef; // TODO: Implement exception throwing rules for (const_iterator it2 = nd.begin(); it2 != nd.end(); ++it2) { std::string key; it2->first >> key; if (key == "distribution") { readScalarOrBitset< DepositDistribution, CountDist >(it2->second, &MineralsYAMLReaderImpl::readDistribution, genesis.distributions); } else if (key == "abundance") { it2->second >> genesis.abundance; } else if (key == "size") { it2->second >> genesis.size; } else if (key == "association") { readScalarOrSequence(it2->second, &MineralsYAMLReaderImpl::readAssociation, genesis.associations); } else if (key == "host") { readAssociation(it2->second, genesis.host); } else if (key == "environment") { readScalarOrSequence(it2->second, &MineralsYAMLReaderImpl::readEnvironment, genesis.environments); } else continue; } } void MineralsYAMLReaderImpl::readMineralDef( const YAML::Node &nd, mars::ptr & mineral ) { using namespace YAML; assert(mineral != NULL); this->_defPetroDef = new PetrogenyDef(); try { readGenesis(nd["deposit"], *this->_defPetroDef); } catch (YAML::TypedKeyNotFound &) {} for (const_iterator it = nd.begin(); it != nd.end(); ++it) { std::string key; const YAML::Node & val = it->second; it->first >> key; if (key == "mineral") val >> mineral->name; else if (key == "boiling_point") val >> mineral->boiling_point; else if (key == "melting_point") val >> mineral->melting_point; else if (key == "triple_point") val >> mineral->triple_point; else if (key == "critical_point") val >> mineral->critical_point; else if (key == "sublimation_point") val >> mineral->sublimation_point; else if (key == "geochemistry") readScalarOrSequence(val, &MineralsYAMLReaderImpl::readYield, mineral->yields); else if (key == "genesis") readScalarOrSequence(val, &MineralsYAMLReaderImpl::readGenesis, mineral->genesis); else if (key == "class") val >> mineral->clazz; } delete this->_defPetroDef; } void MineralsYAMLReaderImpl::readClassDisposition( const YAML::Node &nd, MineralClass::Disposition & disposition ) { using namespace YAML; for (const_iterator it = nd.begin(); it != nd.end(); ++it) { try { std::string key; it->first >> key; if (key == "silica") { strToEnumOrPtSc(it->second, disposition.silica.base, disposition.silica.numeric, "ultra-mafic", Silica_UltraMafic, "mafic", Silica_Mafic, "intermediate", Silica_Intermediate, "inter-felsic", Silica_InterFelsic, "felsic", Silica_Felsic, NULL ); } else if (key == "origin") { strToEnum(it->second, disposition.origin, "volcanic", Origin_Volcanic, "subvolcanic", Origin_Subvolcanic, "plutonic", Origin_Plutonic, "meteoritic", Origin_Meteoritic, NULL ); } else if (key == "temperature") { it->second >> disposition.temperature; } else if (key == "pressure") { it->second >> disposition.pressure; } else if (key == "sediment") { readScalarOrBitset (it->second, &MineralsYAMLReaderImpl::readSediment, disposition.sediment); } else if (key == "weathered") { it->second >> disposition.weathered; } } catch (YAML::RepresentationException &) { } } } void MineralsYAMLReaderImpl::readAssociation( const YAML::Node & nd, MineralReference & assoc ) { using namespace YAML; std::string name; if (nd.Type() == NodeType::Map) { for (const_iterator it = nd.begin(); it != nd.end(); ++it) { std::string key; it->first >> key; if (key == "mineral") it->second >> assoc.mineral; else if (key == "distribution") readScalarOrBitset< DepositDistribution, CountDist > (it->second, &MineralsYAMLReaderImpl::readDistribution, assoc.distributions); } } else nd >> assoc.mineral; } void MineralsYAMLReaderImpl::readGroupDef( IMineralsDatabase * pMinDB, const YAML::Node & nd, mars::ptr & group ) { using namespace YAML; for (const_iterator it = nd.begin(); it != nd.end(); ++it) { std::string key; it->first >> key; if (key == "group") { it->second >> group->name; } else if (key == "members") { for (const_iterator itMemb = it->second.begin(); itMemb != it->second.end(); ++itMemb) { if (itMemb->Type() == NodeType::Scalar) { std::string sRefName; *itMemb >> sRefName; group->members.push_back(sRefName); } else { mars::ptr mineral = new MineralDef(); readMineralDef(*itMemb, mineral); group->members.push_back (pMinDB->addMineral(mineral)); } } } } } void MineralsYAMLReaderImpl::readEnvironment( const YAML::Node & nd, MinClassPtr & clazz ) { nd >> clazz; } void MineralsYAMLReaderImpl::readDistribution( const YAML::Node & nd, DepositDistribution & distribution ) { strToEnum (nd, distribution, "cluster", Dist_Cluster, "vein", Dist_Vein, "sill", Dist_Sill, "dike", Dist_Dike, "layer", Dist_Layer, "laccolith", Dist_Laccolith, NULL ); } void MineralsYAMLReaderImpl::readSediment( const YAML::Node & nd, Sediment & sediment ) { strToEnum (nd, sediment, "gravel", Sediment_Gravel, "sand", Sediment_Sand, "sandy-silt", Sediment_SandySilt, "silt", Sediment_Silt, "silty-clay", Sediment_SiltyClay, "clay", Sediment_Clay, "evaporite", Sediment_Evaporite, NULL ); } bool MineralsYAMLReaderImpl::load (IMineralsDatabase * pMinDB) { using namespace YAML; try { YAML::Node nd; do { nd = Load(_input); if (nd.Type() == NodeType::Map) { std::string type; for (const_iterator it = nd.begin(); it != nd.end(); ++it) { std::string key; it->first >> key; if (key == "mineral") { type = key; break; } else if (key == "class") { type = key; } else if (key == "group") { type = key; } } if (type == "mineral") { mars::ptr mineral = new MineralDef(); readMineralDef(nd, mineral); pMinDB->addMineral(mineral); } else if (type == "class") { mars::ptr rock = new MineralClass(); readClassDefinition(nd, rock); pMinDB->addClass(rock); } else if (type == "group") { mars::ptr group = new MineralGroupDef(); readGroupDef(pMinDB, nd, group); pMinDB->addGroup (group); } } } while (!nd.IsNull()); return true; } catch (YAML::RepresentationException &) { return false; } } MineralsYAMLReader::MineralsYAMLReader( const char * szFile, ... ) : _pifs(new FileList()) { va_list vaFiles; const char * szIncer = szFile; va_start(vaFiles, szFile); while (szIncer != NULL) { _pifs->push_back(new std::ifstream(szIncer, std::ios::in)); szIncer = va_arg(vaFiles, const char *); } va_end(vaFiles); } MineralsYAMLReader::~MineralsYAMLReader() { for (std::vector< std::ifstream * >::iterator i = _pifs->begin(); i != _pifs->end(); ++i) delete *i; delete _pifs; } bool MineralsYAMLReader::load( IMineralsDatabase * pMinDB ) { bool b = true; for (std::vector< std::ifstream * >::iterator iFile = _pifs->begin(); iFile != _pifs->end(); ++iFile) { MineralsYAMLReaderImpl impl(**iFile); b = b && impl.load(pMinDB); } return b; } }