Adaptyst
A comprehensive and architecture-agnostic performance analysis tool
Loading...
Searching...
No Matches
output.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 CERN
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#ifndef ADAPTYST_OUTPUT_HPP_
5#define ADAPTYST_OUTPUT_HPP_
6
7#include <filesystem>
8#include <nlohmann/json.hpp>
9#include <mutex>
10#include <fstream>
11#include <boost/hana.hpp>
12#include <boost/hana/ext/std/tuple.hpp>
13
14namespace adaptyst {
15 namespace fs = std::filesystem;
16 namespace hana = boost::hana;
17
23 protected:
24 nlohmann::json metadata;
25
26 public:
28 this->metadata = nlohmann::json::object();
29 }
30
39 template<class T>
40 void set_metadata(std::string key, T value,
41 bool save = true) {
42 if (this->metadata[key] != value) {
43 this->metadata[key] = value;
44
45 if (save) {
46 this->save_metadata();
47 }
48 }
49 }
50
61 template<class T>
62 T get_metadata(std::string key, T default_value) {
63 return this->metadata.value(key, default_value);
64 }
65
74 template<class T>
75 T get_metadata(std::string key) {
76 return this->metadata[key].get<T>();
77 }
78
83 virtual void save_metadata() = 0;
84 };
85
90 class Path : public ObjectWithMetadata {
91 friend class File;
92
93 private:
94 fs::path path;
95
96 void setup(fs::path path) {
97 this->path = fs::absolute(path);
98 try {
99 fs::create_directories(this->path);
100 } catch (std::exception &e) {
101 throw std::runtime_error("Could not create directory " +
102 this->path.string() + ": " +
103 std::string(e.what()));
104 }
105
106 fs::path metadata_path = this->path / "dirmeta.json";
107
108 if (fs::exists(metadata_path)) {
109 std::ifstream metadata_stream(metadata_path);
110
111 if (!metadata_stream) {
112 throw std::runtime_error("Could not open " +
113 (this->path / "dirmeta.json").string() +
114 " for reading!");
115 }
116
117 std::string json_str((std::istreambuf_iterator<char>(metadata_stream)),
118 std::istreambuf_iterator<char>());
119 this->metadata = nlohmann::json::parse(json_str);
120 }
121 }
122
123 public:
129 Path(fs::path path) {
130 this->setup(path);
131 }
132
138 const char *get_path_name() {
139 return this->path.c_str();
140 }
141
147 Path operator/(std::string second) {
148 return Path(this->path / second);
149 }
150
157 Path operator/(const char *second) {
158 return Path(this->path / second);
159 }
160
165 std::ofstream metadata_stream(this->path / "dirmeta.json");
166
167 if (!metadata_stream) {
168 throw std::runtime_error("Could not open " +
169 (this->path / "dirmeta.json").string() +
170 " for writing!");
171 }
172
173 metadata_stream << this->metadata.dump() << std::endl;
174 }
175 };
176
182 class File : public ObjectWithMetadata {
183 protected:
185 std::string name;
186 std::ifstream istream;
187 std::ofstream ostream;
188
189 public:
199 File(Path &path, std::string name,
200 std::string extension = "",
201 bool truncate = true) : path(path) {
202 this->name = name;
203
204 fs::path new_path = path.path / (name + extension);
205
206 if (fs::exists(new_path)) {
207 if (fs::is_directory(new_path)) {
208 throw std::runtime_error(new_path.string() + " is "
209 "a directory");
210 } else {
211 this->istream = std::ifstream(new_path);
212 }
213 }
214
215 this->ostream = std::ofstream(new_path, std::ios_base::out |
216 (truncate ?
217 std::ios_base::trunc : std::ios_base::app));
218
219 if (!this->ostream) {
220 throw std::runtime_error("Could not open " +
221 new_path.string() +
222 " for writing!");
223 }
224
225 fs::path metadata_path = path.path / ("meta_" + this->name + ".json");
226
227 if (fs::exists(metadata_path)) {
228 std::ifstream metadata_stream(metadata_path);
229
230 if (!metadata_stream) {
231 throw std::runtime_error("Could not open " +
232 (path.path / ("meta_" + this->name + ".json")).string() +
233 " for reading!");
234 }
235
236 std::string json_str((std::istreambuf_iterator<char>(metadata_stream)),
237 std::istreambuf_iterator<char>());
238 this->metadata = nlohmann::json::parse(json_str);
239 }
240 }
241
242 File &operator=(File &&source) {
243 this->path = source.path;
244 this->name = source.name;
245 this->istream = std::move(source.istream);
246 this->ostream = std::move(source.ostream);
247 this->metadata.swap(source.metadata);
248 return *this;
249 }
250
256 std::ifstream &get_istream() {
257 return this->istream;
258 }
259
265 std::ofstream &get_ostream() {
266 return this->ostream;
267 }
268
273 fs::path metadata_path = path.path / ("meta_" + this->name + ".json");
274
275 std::ofstream metadata_stream(metadata_path);
276
277 if (!metadata_stream) {
278 throw std::runtime_error("Could not open " + metadata_path.string() +
279 " for writing!");
280 }
281
282 metadata_stream << this->metadata.dump() << std::endl;
283 }
284 };
285
286 template<typename T>
287 concept is_pair = requires {
288 typename T::first_type;
289 typename T::second_type;
290 } && std::is_same_v<T, std::pair<typename T::first_type,
291 typename T::second_type> >;
292
293 template<typename T>
294 concept is_tuple = requires {
295 std::tuple_size<T>::value;
296 };
297
303 template<class T>
304 class Array : public File {
305 private:
306 std::vector<T> vec;
307
308 public:
315 Array(Path &path, std::string name) : File(path, name, ".dat", false) {
316 while (this->istream && !this->istream.eof()) {
317 T val;
318
319 if constexpr (is_pair<T>) {
320 this->istream >> val.first;
321 this->istream >> val.second;
322 } else if constexpr (is_tuple<T>) {
323 hana::for_each(val, [&](auto &item) {
324 this->istream >> item;
325 });
326 } else {
327 this->istream >> val;
328 }
329
330 if (this->istream) {
331 vec.push_back(val);
332 }
333 }
334 }
335
343 T operator[](int index) {
344 return this->vec[index];
345 }
346
352 int size() {
353 return this->vec.size();
354 }
355
362 void push_back(T val) {
363 this->vec.push_back(val);
364
365 if constexpr (is_pair<T>) {
366 this->ostream << val.first << " " << val.second << std::endl;
367 } else if constexpr (is_tuple<T>) {
368 std::stringstream str_stream;
369 hana::for_each(val, [&](auto &item) {
370 str_stream << item << " ";
371 });
372
373 std::string to_write = str_stream.str();
374 to_write = to_write.substr(0, to_write.length() - 1);
375
376 this->ostream << to_write << std::endl;
377 } else {
378 this->ostream << val << std::endl;
379 }
380 }
381 };
382}
383
384#endif
T operator[](int index)
Definition output.hpp:343
void push_back(T val)
Definition output.hpp:362
int size()
Definition output.hpp:352
Array(Path &path, std::string name)
Definition output.hpp:315
File & operator=(File &&source)
Definition output.hpp:242
File(Path &path, std::string name, std::string extension="", bool truncate=true)
Definition output.hpp:199
std::ofstream ostream
Definition output.hpp:187
std::string name
Definition output.hpp:185
std::ifstream & get_istream()
Definition output.hpp:256
Path & path
Definition output.hpp:184
std::ofstream & get_ostream()
Definition output.hpp:265
void save_metadata()
Definition output.hpp:272
std::ifstream istream
Definition output.hpp:186
virtual void save_metadata()=0
ObjectWithMetadata()
Definition output.hpp:27
nlohmann::json metadata
Definition output.hpp:24
T get_metadata(std::string key)
Definition output.hpp:75
void set_metadata(std::string key, T value, bool save=true)
Definition output.hpp:40
T get_metadata(std::string key, T default_value)
Definition output.hpp:62
Definition output.hpp:90
void save_metadata()
Definition output.hpp:164
const char * get_path_name()
Definition output.hpp:138
Path operator/(const char *second)
Definition output.hpp:157
friend class File
Definition output.hpp:91
Path(fs::path path)
Definition output.hpp:129
Path operator/(std::string second)
Definition output.hpp:147
Definition output.hpp:287
Definition output.hpp:294
Definition archive.cpp:7