lammps/unittest/force-styles/yaml_reader.h

179 lines
5.5 KiB
C++

/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifndef YAML_READER_H
#define YAML_READER_H
#include "yaml.h"
#include <cstdio>
#include <iostream>
#include <map>
#include <string>
template <typename ConsumerClass> class YamlReader {
private:
enum StateValue {
START,
ACCEPT_KEY,
ACCEPT_VALUE,
STOP,
ERROR,
};
StateValue state;
bool accepted;
std::string key;
std::string basename;
protected:
typedef void (ConsumerClass::*EventConsumer)(const yaml_event_t &event);
std::map<std::string, EventConsumer> consumers;
public:
YamlReader() {}
virtual ~YamlReader() {}
std::string get_basename() const { return basename; }
int parse_file(const std::string &infile)
{
basename = infile;
std::size_t found = basename.rfind(".yaml");
if (found > 0) basename = basename.substr(0, found);
found = basename.find_last_of("/\\");
if (found != std::string::npos) basename = basename.substr(found + 1);
FILE *fp = fopen(infile.c_str(), "r");
yaml_parser_t parser;
yaml_event_t event;
if (!fp) {
std::cerr << "Cannot open yaml file '" << infile << "': " << strerror(errno)
<< std::endl;
return 1;
}
yaml_parser_initialize(&parser);
yaml_parser_set_input_file(&parser, fp);
state = START;
do {
if (!yaml_parser_parse(&parser, &event)) {
state = STOP;
}
if (!consume_event(event)) {
state = STOP;
}
if (accepted) {
if (!consume_key_value(key, event)) {
std::cerr << "Ignoring unknown key/value pair: " << key << " = "
<< event.data.scalar.value << std::endl;
}
}
yaml_event_delete(&event);
} while (state != STOP);
yaml_parser_delete(&parser);
fclose(fp);
return 0;
}
protected:
bool consume_key_value(const std::string &key, const yaml_event_t &event)
{
auto it = consumers.find(key);
ConsumerClass *consumer = dynamic_cast<ConsumerClass *>(this);
if (consumer) {
if (it != consumers.end()) {
// std::cerr << "Loading: " << key << std::endl;
(consumer->*(it->second))(event);
return true;
}
std::cerr << "UNKNOWN" << std::endl;
} else {
std::cerr << "ConsumerClass is not valid" << std::endl;
}
return false;
}
bool consume_event(yaml_event_t &event)
{
accepted = false;
switch (state) {
case START:
switch (event.type) {
case YAML_MAPPING_START_EVENT:
state = ACCEPT_KEY;
break;
case YAML_SCALAR_EVENT:
case YAML_SEQUENCE_START_EVENT:
state = ERROR;
break;
case YAML_STREAM_END_EVENT:
state = STOP;
break;
case YAML_STREAM_START_EVENT:
case YAML_DOCUMENT_START_EVENT:
case YAML_DOCUMENT_END_EVENT:
// ignore
break;
default:
std::cerr << "UNHANDLED YAML EVENT: " << event.type << std::endl;
state = ERROR;
break;
}
break;
case ACCEPT_KEY:
switch (event.type) {
case YAML_SCALAR_EVENT:
key = (char *)event.data.scalar.value;
state = ACCEPT_VALUE;
break;
case YAML_MAPPING_END_EVENT:
state = STOP;
break;
default:
std::cerr << "UNHANDLED YAML EVENT (key): " << event.type
<< "\nVALUE: " << event.data.scalar.value << std::endl;
state = ERROR;
break;
}
break;
case ACCEPT_VALUE:
switch (event.type) {
case YAML_SCALAR_EVENT:
accepted = true;
state = ACCEPT_KEY;
break;
default:
std::cerr << "UNHANDLED YAML EVENT (value): " << event.type
<< "\nVALUE: " << event.data.scalar.value << std::endl;
state = ERROR;
break;
}
break;
case ERROR:
case STOP:
break;
}
return (state != ERROR);
}
};
#endif