ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
Loading...
Searching...
No Matches
FRW_fileReadWrite.hpp
1#pragma once
2#include <algorithm>
3#include <fstream>
4#include <iostream>
5#include <sstream>
6#include <string>
7#include <tuple>
8#include <type_traits>
9#include <utility>
10#include <vector>
14namespace IO::FRW {
15
16//==============================================================================
17// Uses compile-time recursion to get access to elements of tuple.
18// Specifically, string-streams data from a string vector into tuple.
19// Works with a tuple of references, i.e., std::forward_as_tuple
20// Idea from:
21// https://stackoverflow.com/questions/1198260/iterate-over-tuple/23142715
22template <std::size_t I = 0, typename... Tp>
23inline typename std::enable_if<I == sizeof...(Tp), void>::type
24stringstreamVectorIntoTuple(const std::vector<std::string> &,
25 std::tuple<Tp...> &) {}
26
27template <std::size_t I = 0, typename... Tp>
28 inline typename std::enable_if <
29 I<sizeof...(Tp), void>::type
30 stringstreamVectorIntoTuple(const std::vector<std::string> &lst,
31 std::tuple<Tp...> &t) {
32 if (I > lst.size())
33 std::cerr << "\nFAIL 34 in FRW: list shorter than tuple\n";
34 std::stringstream(lst[I]) >> std::get<I>(t);
35 stringstreamVectorIntoTuple<I + 1, Tp...>(lst, t);
36}
37
38//==============================================================================
39inline std::vector<std::string> readInputFile_byEntry(const std::string &fname)
40// Reads each item (space separated) from a file into a string vector
41// Any text after a '#' or '!' are treated as comments and ignored
42// (can come anywhere in the line)
43{
44 std::vector<std::string> entry_list;
45 std::ifstream file(fname);
46 std::string line;
47 while (getline(file, line) && (file.is_open())) { // redundant?
48 std::stringstream ss(line);
49 std::string entry;
50 while (ss >> entry) {
51 if (entry.at(0) == '!' || entry.at(0) == '#')
52 break;
53 if (entry.size() >= 2 && entry.at(0) == '/' && entry.at(1) == '/')
54 break;
55 entry_list.push_back(entry);
56 }
57 }
58 return entry_list;
59}
60
61//==============================================================================
62inline std::vector<std::string> readInputFile_byLine(const std::string &fname)
63// Reads each line from a file into a string vector
64// Lines beginning with '!' or '#' are comments
65{
66 std::vector<std::string> entry_list;
67 std::ifstream file(fname);
68 std::string line;
69 while (getline(file, line) && (file.is_open())) { // redundant?
70 if (line == "")
71 continue;
72 if (line.at(0) == '!' || line.at(0) == '#')
73 continue;
74 if (line.size() >= 2 && line.at(0) == '/' && line.at(1) == '/')
75 continue;
76 entry_list.push_back(line);
77 }
78 return entry_list;
79}
80
81//==============================================================================
82inline std::vector<std::pair<double, double>>
83readFile_xy_VoP(const std::string &fname)
84// Reads each line from a file into a vector of {x,y} points
85// Lines beginning with '!' or '#' are comments
86// Could generalise this to any number of points?
87{
88 std::vector<std::pair<double, double>> out_list;
89 std::ifstream file(fname);
90 std::string line = "";
91 while (getline(file, line) && (file.is_open())) { // redundant?
92 if (line == "")
93 continue;
94 if (line.at(0) == '!' || line.at(0) == '#')
95 continue;
96 if (line.size() >= 2 && line.at(0) == '/' && line.at(1) == '/')
97 continue;
98 std::stringstream ss(line);
99 double x, y;
100 ss >> x >> y;
101 out_list.emplace_back(x, y);
102 }
103 return out_list;
104}
105//------------------------------------------------------------------------------
106inline std::pair<std::vector<double>, std::vector<double>>
107readFile_xy_PoV(const std::string &fname)
108// Reads each line from a file;
109// Returns a pair of a vectors {{x},{y}}
110// Lines beginning with '!' or '#' are comments
111{
112 std::pair<std::vector<double>, std::vector<double>> out_list;
113 std::ifstream file(fname);
114 std::string line = "";
115 while (getline(file, line) && (file.is_open())) { // redundant?
116 if (line == "")
117 continue;
118 if (line.at(0) == '!' || line.at(0) == '#')
119 continue;
120 if (line.size() >= 2 && line.at(0) == '/' && line.at(1) == '/')
121 continue;
122 std::stringstream ss(line);
123 double x, y;
124 ss >> x >> y;
125 out_list.first.push_back(x);
126 out_list.second.push_back(y);
127 }
128 return out_list;
129}
130
131//------------------------------------------------------------------------------
132inline void writeFile_xy(const std::vector<double> &x,
133 const std::vector<double> &y,
134 const std::string &fname) {
135 //
136 if (x.size() != y.size()) {
137 std::cout << "Warning 139 in FRW: trying to write {x,y} vectors of "
138 "different lengths!\n";
139 }
140 std::ofstream file(fname);
141 auto max = std::min(x.size(), y.size());
142 for (auto i = 0ul; i < max; ++i) {
143 file << x[i] << " " << y[i] << "\n";
144 }
145 //
146}
147
148//==============================================================================
150inline std::string readInputFile(const std::string &fname) {
151 std::ifstream f(fname); // taking file as inputstream
152 std::string str;
153 if (f) {
154 std::ostringstream ss;
155 ss << f.rdbuf(); // reading data
156 str = ss.str();
157 }
158 return str;
159}
160
161//==============================================================================
162inline void removeBlockComments(std::string &input) {
163 for (auto posi = input.find("/*"); posi != std::string::npos;
164 posi = input.find("/*")) {
165 auto posf = input.find("*/");
166 if (posf != std::string::npos) {
167 input = input.substr(0, posi) + input.substr(posf + 2);
168 } else {
169 input = input.substr(0, posi);
170 }
171 }
172}
173//==============================================================================
174inline std::string removeCommentsAndSpaces(const std::string &input)
175// Note: also squashes lines, except for semi-colons
176{
177 std::string lines = "";
178 {
179 std::string line;
180 std::stringstream stream1(input);
181 while (std::getline(stream1, line, '\n')) {
182 auto comm1 = line.find('!'); // nb: char, NOT string literal!
183 auto comm2 = line.find('#');
184 auto comm3 = line.find("//"); // str literal here
185 auto comm = std::min(comm1, std::min(comm2, comm3));
186 lines += line.substr(0, comm);
187 }
188 }
189
190 removeBlockComments(lines);
191
192 // remove spaces
193 lines.erase(std::remove_if(lines.begin(), lines.end(),
194 [](unsigned char x) { return x == ' '; }),
195 lines.end());
196 // remove tabs
197 lines.erase(std::remove_if(lines.begin(), lines.end(),
198 [](unsigned char x) { return x == '\t'; }),
199 lines.end());
200
201 // remove ' and "
202 lines.erase(std::remove_if(lines.begin(), lines.end(),
203 [](unsigned char x) { return x == '\''; }),
204 lines.end());
205 lines.erase(std::remove_if(lines.begin(), lines.end(),
206 [](unsigned char x) { return x == '\"'; }),
207 lines.end());
208
209 return lines;
210}
211
212//==============================================================================
213inline std::vector<std::pair<std::string, std::string>>
214splitInput_byBraces(const std::string &input) {
215
216 std::vector<std::pair<std::string, std::string>> output;
217
218 auto lines = removeCommentsAndSpaces(input);
219
220 auto find_close = [&lines](auto open) {
221 auto next_open = lines.find('{', open + 1);
222 auto next_close = lines.find('}', open + 1);
223 auto next = std::min(next_open, next_close);
224 if (next == next_close || next == std::string::npos)
225 return next;
226 int depth = 1;
227 while (depth > 0) {
228 next_open = lines.find('{', next + 1);
229 next_close = lines.find('}', next + 1);
230 next = std::min(next_open, next_close);
231 if (next == next_close)
232 --depth;
233 if (next == next_open)
234 ++depth;
235 }
236 next = lines.find('}', next + 1);
237 return next;
238 };
239
240 std::size_t previous_end = 0;
241 while (true) {
242 auto beg = lines.find('{', previous_end);
243 auto end = find_close(beg);
244 if (beg == std::string::npos)
245 break;
246 if (end == std::string::npos) {
247 std::cerr << "\nFAIL 114 in FRW: Bad file format (missing '}'?)\n";
248 break;
249 }
250 auto identifier = lines.substr(previous_end, beg - previous_end);
251 auto options = lines.substr(beg + 1, end - beg - 1);
252 output.push_back(std::make_pair(identifier, options));
253 previous_end = end + 1;
254 }
255
256 return output;
257}
258
259//==============================================================================
260inline std::vector<std::string> splitInput_bySemiColon(const std::string &input)
261// ...
262{
263 std::vector<std::string> entry_list;
264
265 auto lines = removeCommentsAndSpaces(input);
266
267 // BUT, treat anything inside [] brackets as single
268
269 // after removing comments, break up by ';'
270 // std::stringstream stream2(lines);
271 // std::string entry;
272 // while (std::getline(stream2, entry, ';')) {
273 // entry_list.push_back(entry);
274 // }
275
276 // dumb hack to ingore first braket '['..
277 std::size_t start = (input.size() > 0 && input[0] == '{') ? 1 : 0;
278
279 // std::size_t start = 0;
280 while (true) {
281 // Check if we find a ';' or an open braket '[' first:
282 const auto bkt = input.find('{', start);
283 const auto semic = input.find(';', start);
284 const auto bracketQ = bkt < semic;
285
286 // If no braket, 'end' of string is semicolon ';'.
287 // If we do have brakets, end is "];"
288 const auto end = bracketQ ? input.find("};", start) + 1 : semic;
289 if (end == std::string::npos)
290 break;
291 entry_list.push_back(input.substr(start, end - start));
292 start = end + 1;
293 }
294
295 return entry_list;
296}
297
298//==============================================================================
299template <typename... Tp>
300void setInputParameters(const std::string &infile, std::tuple<Tp...> &tp) {
301 auto input = readInputFile_byEntry(infile);
302 if (sizeof...(Tp) > input.size()) {
303 // Note: for now, I allow a longer-than-needed input list.
304 // This allows us to not have to comment out all the crap below
305 // the input file..
306 std::cerr << "\nFail 71 in FRW: Wrong number of input parameters? "
307 << "Reading from file: " << infile << ". Expected "
308 << sizeof...(Tp) << " arguments"
309 << ", but got " << input.size() << ".\n";
310 return;
311 }
312 stringstreamVectorIntoTuple(input, tp);
313}
314
315//==============================================================================
316enum RoW { read, write };
317
318// XXX Wrap these into a class. AND make explicit which types are/aren't
319// allowed!
320
321inline void open_binary(std::fstream &stream, const std::string &fname,
322 RoW row) {
323 switch (row) {
324 case write:
325 stream.open(fname, std::ios_base::out | std::ios_base::binary);
326 break;
327 case read:
328 stream.open(fname, std::ios_base::in | std::ios_base::binary);
329 break;
330 default:
331 std::cout << "\nFAIL 16 in FRW\n";
332 }
333}
334
335inline bool file_exists(const std::string &fileName) {
336 if (fileName == "")
337 return false;
338 std::ifstream infile(fileName);
339 return infile.good();
340}
341
345template <typename T, typename... Types>
346void rw_binary(std::fstream &stream, RoW row, std::vector<T> &value,
347 Types &...values) {
348 binary_rw_vec(stream, value, row);
349 if constexpr (sizeof...(values) != 0)
350 rw_binary(stream, row, values...);
351}
352
355template <typename T, typename... Types>
356void rw_binary(std::fstream &stream, RoW row, T &value, Types &...values) {
357 if constexpr (std::is_same_v<T, std::string>)
358 binary_str_rw(stream, value, row);
359 else
360 binary_rw(stream, value, row);
361 if constexpr (sizeof...(values) != 0)
362 rw_binary(stream, row, values...);
363}
364
365// make "private" behind 'helper' namespace: used in old code still
366template <typename T>
367void binary_rw(std::fstream &stream, T &value, RoW row) {
368 switch (row) {
369 case write:
370 stream.write(reinterpret_cast<const char *>(&value), sizeof(T));
371 break;
372 case read:
373 stream.read(reinterpret_cast<char *>(&value), sizeof(T));
374 break;
375 default:
376 std::cout << "\nFAIL 32 in FRW\n";
377 }
378}
379
380// For vector. {works with Vector of vectors also}
381template <typename T>
382void binary_rw_vec(std::fstream &stream, std::vector<T> &value, RoW row) {
383 std::size_t size = value.size();
384 binary_rw(stream, size, row);
385 if (row == read)
386 value.resize(size);
387 for (auto &x : value) {
388 rw_binary(stream, row, x);
389 }
390}
391
392// make "private" behind 'helper' namespace: used in old code still
393inline void binary_str_rw(std::fstream &stream, std::string &value, RoW row) {
394 if (row == write) {
395 std::size_t temp_len = value.length();
396 stream.write(reinterpret_cast<const char *>(&temp_len),
397 sizeof(std::size_t));
398 stream.write(value.c_str(), long(value.length()));
399 } else if (row == read) {
400 std::size_t temp_len;
401 stream.read(reinterpret_cast<char *>(&temp_len), sizeof(std::size_t));
402 char *tvalue = new char[temp_len + 1];
403 stream.read(tvalue, long(temp_len));
404 tvalue[temp_len] = '\0'; // null 'end of string' character
405 value = tvalue;
406 delete[] tvalue;
407 } else {
408 std::cout << "\nFAIL 55 in FRW\n";
409 }
410}
411
412} // namespace IO::FRW
Definition FRW_fileReadWrite.hpp:14
void rw_binary(std::fstream &stream, RoW row, std::vector< T > &value, Types &...values)
Function (variadic): reads/writes data from/to binary file. Works for trivial (PoD) types,...
Definition FRW_fileReadWrite.hpp:346
std::string readInputFile(const std::string &fname)
reads entire text file into a string
Definition FRW_fileReadWrite.hpp:150