4 return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
8 std::istringstream iss(s);
10 return (iss >> d) && (iss.eof());
14 return s ==
"true" || s ==
"false";
22 std::istringstream stream(input);
23 return parseYAMLDBNode(stream, 0);
26std::shared_ptr<DBNode> YAMLParser::parseYAMLDBNode(std::istringstream& stream,
int indentLevel) {
27 auto node = std::make_shared<DBNode>();
30 while (std::getline(stream, line)) {
34 int currentIndent = countLeadingSpaces(line);
35 if (currentIndent < indentLevel) {
36 stream.seekg(-
static_cast<int>(line.size()) - 1, std::ios_base::cur);
41 if (line.empty() || line[0] ==
'#')
continue;
44 processList(node, stream, currentIndent, line);
45 }
else if (line.find(
":") != std::string::npos) {
46 processKeyValue(line, node, stream, currentIndent + 2);
52void YAMLParser::processKeyValue(
const std::string& line, std::shared_ptr<DBNode>& node, std::istringstream& stream,
int indentLevel) {
53 size_t colonPos = line.find(
":");
54 std::string key = trim(line.substr(0, colonPos));
55 std::string value = trim(line.substr(colonPos + 1));
57 auto childDBNode = parseYAMLDBNode(stream, indentLevel);
58 node->set(childDBNode, key);
60 node->set(parseScalar(value), key);
64void YAMLParser::processList(std::shared_ptr<DBNode>& node, std::istringstream& stream,
int indentLevel, std::string firstLine) {
65 std::map<BlockName, DBNode::Value> listData;
67 std::string line = firstLine;
71 auto tempDBNode = std::make_shared<DBNode>();
74 if (!first && !std::getline(stream, line)){
75 listData[std::to_string(index)] = tempDBNode->countChildren() != 0 ? tempDBNode : currentDBNode;
83 if (!first && countLeadingSpaces(line) < indentLevel) {
84 stream.seekg(-
static_cast<int>(line.size()) - 1, std::ios_base::cur);
85 listData[std::to_string(index)] = tempDBNode->countChildren() != 0 ? tempDBNode : currentDBNode;
92 if (tempDBNode->countChildren() != 0) {
93 currentDBNode = tempDBNode;
94 tempDBNode = std::make_shared<DBNode>();
96 listData[std::to_string(index)] = currentDBNode;
102 line = trim(line.substr(1));
105 size_t colonPos = line.find(
":");
107 if (colonPos != std::string::npos) {
108 std::string key = trim(line.substr(0, colonPos));
109 std::string value = trim(line.substr(colonPos + 1));
111 auto childDBNode = parseYAMLDBNode(stream, indentLevel + 2);
112 tempDBNode->set(childDBNode, key);
114 tempDBNode->set(parseScalar(value), key);
117 currentDBNode = parseScalar(trim(line));
121 node->setGroup({}, listData);
126DBNode::Value YAMLParser::parseScalar(
const std::string& value) {
127 if (isInteger(value)) {
128 return std::stoi(value);
129 }
else if (isDouble(value)) {
130 return std::stod(value);
131 }
else if (value ==
"true" || value ==
"false") {
132 return value ==
"true";
138int YAMLParser::countLeadingSpaces(
const std::string& str) {
139 return str.find_first_not_of(
' ');
142std::string YAMLParser::trim(
const std::string& str) {
143 size_t first = str.find_first_not_of(
" \t");
144 if (first == std::string::npos)
return "";
145 size_t last = str.find_last_not_of(
" \t");
146 return str.substr(first, last - first + 1);
149bool YAMLParser::isInteger(
const std::string& str) {
150 return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
153bool YAMLParser::isDouble(
const std::string& str) {
155 std::strtod(str.c_str(), &end);
156 return end != str.c_str() && *end ==
'\0';
160bool YAMLParser::isListDBNode(
const std::shared_ptr<DBNode>& node)
const {
161 for (
const auto& [key, _] : node->getGroup({})) {
162 std::string keyStr = key.to_string();
164 if (!std::all_of(keyStr.begin(), keyStr.end(), ::isdigit)) {
171DBNode::Value YAMLParser::parseValue(
const std::string& value)
const {
172 if (value.empty())
return "";
174 if (!value.empty() && std::all_of(value.begin(), value.end(), ::isdigit)) {
175 return std::stoi(value);
178 if (value.find_first_of(
".eE") != std::string::npos) {
180 return parseNumber(value);
184 if (value ==
"true")
return true;
185 if (value ==
"false")
return false;
190double YAMLParser::parseNumber(
const std::string& value)
const {
192 return std::stod(value);
193 }
catch (
const std::exception&) {
194 throw std::runtime_error(
"Invalid numeric format: " + value);
199 std::ofstream file(filename);
201 throw std::runtime_error(
"Unable to open file for writing: " + filename);
202 root->printYAMLToStream(file);
206 throw std::runtime_error(
"Error while writing YAML file: " + filename);
210 std::ifstream file(filename);
211 if (!file.is_open())
throw std::runtime_error(
"Unable to open file for reading");
213 std::ostringstream oss;
215 return parse(oss.str());
bool isBoolean(const std::string &s)
bool isInteger(const std::string &s)
bool isDouble(const std::string &s)
bool parseBool(const std::string &s)
Lightweight YAML parser/serializer for DBNode trees.
std::variant< BlockName, int, double, bool, std::shared_ptr< DBNode >, std::vector< std::shared_ptr< DBNode > > > Value
Variant type used to store values in the tree.
std::shared_ptr< DBNode > readFromFile(const std::string &filename) const override
Reads and parses YAML data from a file.
std::shared_ptr< DBNode > parse(const std::string &input) const override
Parses a YAML string into a DBNode hierarchy.
void writeToFile(const std::string &filename, const std::shared_ptr< DBNode > &root) const override
Writes a DBNode hierarchy to a YAML file.