OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
SDDSParser.cpp
Go to the documentation of this file.
1//
2// Class SDDSParser
3// This class writes column entries of SDDS files.
4//
5// Copyright (c) 2015, Christof Metzger-Kraus, Helmholtz-Zentrum Berlin
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
18#include "Util/SDDSParser.h"
21
22#include <cctype>
23#include <cstddef>
24#include <exception>
25#include <fstream>
26#include <string>
27#include <string_view>
28
30 sddsFileName_m("")
31{ }
32
33SDDS::SDDSParser::SDDSParser(const std::string& input):
34 sddsFileName_m(input)
35{ }
36
37void SDDS::SDDSParser::setInput(const std::string& input) {
38 sddsFileName_m = input;
39}
40
42 sddsData_m.clear();
43 paramNameToID_m.clear();
44 columnNameToID_m.clear();
45
46 std::string contents = readFile();
47
48 // Use simple parser instead of boost::spirit
49 parser::SimpleParser parser(contents);
50 try {
51 sddsData_m = parser.parse();
52 } catch (const std::exception& e) {
53 throw SDDSParserException("SDDSParser::run",
54 std::string("could not parse SDDS file: ") + e.what());
55 }
56
57 // Parse parameter values from the data section, not from file start.
58 std::size_t pos = parser.dataStartPos();
59 const std::size_t len = contents.size();
60 if (pos == std::string::npos) {
61 pos = contents.length();
62 }
63
64 auto skipWSAndComments = [&]() {
66 };
67
68 for (auto& param : sddsData_m.sddsParameters_m) {
69 if (!param.parse(contents, pos)) {
70 throw SDDSParserException("SDDSParser::run",
71 "could not parse parameter value");
72 }
73 skipWSAndComments();
74 }
75
76 // Parse column values row-by-row. A row is only accepted if all columns parse.
77 while (pos < len) {
78 std::size_t rowStart = pos;
79 std::size_t parsedColumns = 0;
80
81 for (auto& col : sddsData_m.sddsColumns_m) {
82 if (!col.parse(contents, pos)) {
83 break;
84 }
85 parsedColumns++;
86 skipWSAndComments();
87 }
88
89 if (parsedColumns == 0) {
90 pos = rowStart;
91 break;
92 }
93
94 if (parsedColumns != sddsData_m.sddsColumns_m.size()) {
95 throw SDDSParserException("SDDSParser::run",
96 "could not parse a complete data row");
97 }
98 }
99
100 paramNameToID_m.reserve(sddsData_m.sddsParameters_m.size());
101 std::size_t param_order = 0;
102 for (const SDDS::parameter &param: sddsData_m.sddsParameters_m) {
103 const std::string name = normalizeKey(*param.name_m);
104 paramNameToID_m.emplace(name, param_order);
105 ++ param_order;
106 }
107
108 columnNameToID_m.reserve(sddsData_m.sddsColumns_m.size());
109 std::size_t col_order = 0;
110 for (const SDDS::column &col: sddsData_m.sddsColumns_m) {
111 const std::string name = normalizeKey(*col.name_m);
112 columnNameToID_m.emplace(name, col_order);
113 ++ col_order;
114 }
115
116 return sddsData_m;
117}
118
120 std::ifstream in(sddsFileName_m, std::ios::binary);
121
122 if (in) {
123 in.seekg(0, std::ios::end);
124 const std::streamsize fileSize = in.tellg();
125 in.seekg(0, std::ios::beg);
126
127 if (fileSize < 0) {
128 throw SDDSParserException("SDDSParser::readSDDSFile",
129 "could not determine size of file '" + sddsFileName_m + "'");
130 }
131
132 std::string contents(static_cast<std::size_t>(fileSize), '\0');
133 if (!contents.empty()) {
134 in.read(contents.data(), fileSize);
135 }
136
137 return contents;
138 }
139
140 throw SDDSParserException("SDDSParser::readSDDSFile",
141 "could not open file '" + sddsFileName_m + "'");
142
143 return std::string("");
144}
145
147SDDS::SDDSParser::getColumnData(const std::string& columnName) const {
148 const int idx = getColumnIndex(columnName);
149 return sddsData_m.sddsColumns_m[idx].values_m;
150}
151
152int SDDS::SDDSParser::getColumnIndex(const std::string& col_name) const {
153 const std::string normalizedName = normalizeKey(col_name);
154 const auto it = columnNameToID_m.find(normalizedName);
155 if (it != columnNameToID_m.end()) {
156 return static_cast<int>(it->second);
157 }
158 throw SDDSParserException("SDDSParser::getColumnIndex",
159 "could not find column '" + col_name + "'");
160}
161
162std::string SDDS::SDDSParser::normalizeKey(std::string_view value) {
163 std::size_t firstUppercase = std::string_view::npos;
164 for (std::size_t index = 0; index < value.size(); ++index) {
165 if (std::isupper(static_cast<unsigned char>(value[index]))) {
166 firstUppercase = index;
167 break;
168 }
169 }
170
171 if (firstUppercase == std::string_view::npos) {
172 return std::string(value);
173 }
174
175 std::string lower(value);
176 for (std::size_t index = firstUppercase; index < lower.size(); ++index) {
177 lower[index] = static_cast<char>(std::tolower(static_cast<unsigned char>(lower[index])));
178 }
179
180 return lower;
181}
const std::string name
FILECONTENTS * readFile(const char filename[])
Definition read.cpp:44
std::vector< variant_t > columnData_t
Definition ast.hpp:51
void skipWhitespaceAndComments(std::string_view input, std::size_t &pos)
Definition skipper.hpp:28
std::string readFile()
static std::string normalizeKey(std::string_view value)
int getColumnIndex(const std::string &col_name) const
void setInput(const std::string &input)
const ast::columnData_t & getColumnData(const std::string &columnName) const
void clear()
Definition file.hpp:43
std::size_t dataStartPos() const