Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
fortran_io.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
23#include <array>
24#include <fstream>
25#include <sstream>
26#include <stdexcept>
27#include <string>
28#include <utility>
29#include <vector>
30
31namespace shambase {
32
37
46 inline void check_fortran_4byte(std::basic_stringstream<byte> &buffer, i32 fortran_byte) {
47 i32 new_check = 0;
48
49 shambase::stream_read(buffer, new_check);
50
51 if (new_check != fortran_byte) {
52 throw shambase::make_except_with_loc<std::runtime_error>("fortran 4 bytes invalid");
53 }
54
56 }
57
69 inline i32 read_fortran_4byte(std::basic_stringstream<byte> &buffer) {
70 i32 check;
71 shambase::stream_read(buffer, check);
72 return check;
73 }
74
76 std::basic_stringstream<byte> data;
77
79 u64 length;
80
87 template<class T>
88 inline void _write(T arg) {
89 stream_write(data, arg);
90 }
91
98 template<class T>
99 inline void _read(T &arg) {
100 stream_read(data, arg);
101 }
102
110 template<class T, int N>
111 inline void _read(std::array<T, N> &vec) {
112 for (u32 i = 0; i < N; i++) {
113 stream_read(data, vec[i]);
114 }
115 }
116
124 template<class T, int N>
125 inline void _write(std::array<T, N> &vec) {
126 for (u32 i = 0; i < N; i++) {
127 stream_write(data, vec[i]);
128 }
129 }
130
131 public:
133 using fort_real = f64;
134
136 using fort_int = int;
137
144 explicit FortranIOFile(std::basic_stringstream<byte> &&data_in, u64 length)
145 : data(std::forward<std::basic_stringstream<byte>>(data_in)), length(length) {
146
147 // Set the internal buffer to the beginning of the buffer
148 data.seekg(0);
149 }
150
151 FortranIOFile() = default;
152
158 inline std::basic_stringstream<byte> &get_internal_buf() {
159 // Return a reference to the internal buffer
160 return data;
161 }
162
175 template<class... Args>
176 inline void write(Args &...args) {
177 i32 linebytecount = ((sizeof(args)) + ...);
178 stream_write(data, linebytecount);
179 ((_write(args)), ...);
180 stream_write(data, linebytecount);
181 }
182
194 template<class... Args>
195 inline void read(Args &...args) {
196 u64 linebytecount = ((sizeof(args)) + ...);
197 i32 check = read_fortran_4byte(data);
198 if (check != linebytecount) {
199 throw_with_loc<std::runtime_error>("the byte count is not correct");
200 }
201 ((_read(args)), ...);
202 check_fortran_4byte(data, check);
203 }
204
216 inline void read_fixed_string(std::string &s, u32 len) {
217 s.resize(len);
218 i32 check = read_fortran_4byte(data);
219 if (check != len) {
220 throw_with_loc<std::runtime_error>("the byte count is not correct");
221 }
222 data.read(reinterpret_cast<byte *>(s.data()), len * sizeof(char));
223 check_fortran_4byte(data, check);
224 }
225
237 inline void write_fixed_string(std::string &s, u32 len) {
238 stream_write(data, len);
239 data.write(reinterpret_cast<byte *>(s.data()), len * sizeof(char));
240 stream_write(data, len);
241 }
242
255 inline void read_string_array(std::vector<std::string> &svec, u32 strlen, u32 str_count) {
256
258 i32 check = read_fortran_4byte(data);
259 if (check != totlen) {
260 throw_with_loc<std::runtime_error>("the byte count is not correct");
261 }
262
263 svec.resize(str_count);
264
265 for (u32 i = 0; i < str_count; i++) {
266 svec[i].resize(strlen); // Resize the string to the correct size
267 data.read(reinterpret_cast<byte *>(svec[i].data()), strlen * sizeof(char));
268 }
269
270 check_fortran_4byte(data, check);
271 }
272
285 inline void write_string_array(std::vector<std::string> &svec, u32 strlen, u32 str_count) {
286
287 i32 totlen = strlen * str_count; // Total length of the array
288
289 stream_write(data, totlen); // Write the total length as a 4-byte integer
290
291 for (u32 i = 0; i < str_count; i++) {
292 // Write each string to the buffer
293 data.write(reinterpret_cast<byte *>(svec[i].data()), strlen * sizeof(char));
294 }
295
296 stream_write(data, totlen); // Write the total length again as a 4-byte integer
297 }
298
311 template<class T>
312 inline void read_val_array(std::vector<T> &vec, u32 val_count) {
313
314 u64 totlen = sizeof(T) * val_count; // Total length of the array
315 i32 check = read_fortran_4byte(data); // Read the total length
316
317 if (check != totlen) { // Make sure the byte count matches
318 throw_with_loc<std::runtime_error>( // Throw an exception if not
319 "the byte count is not correct");
320 }
321
322 vec.resize(val_count); // Resize the output array to the correct size
323
324 for (u32 i = 0; i < val_count; i++) { // Read each value from the buffer
325 stream_read(data, vec[i]);
326 }
327
328 check_fortran_4byte(data, check); // Check the byte count again
329 }
330
345 template<class T>
346 inline void write_val_array(std::vector<T> &vec, u32 val_count) {
347 if (val_count > vec.size()) {
349 "val count is higher than vec size");
350 }
351 i32 totlen = sizeof(T) * val_count;
352 stream_write(data, totlen); // Write the total length of the array
353
354 for (u32 i = 0; i < val_count; i++) { // Write each value in the array
355 stream_write(data, vec[i]);
356 }
357
358 stream_write(data, totlen); // Write the total length again
359 }
360
369 inline bool finished_read() { return length == data.tellg(); }
370
378 inline void write_to_file(std::string fname) {
379 std::ofstream out_f(fname, std::ios::binary);
380
381 if (out_f) {
382 // Copy the contents of the internal streambuf to the file
383 out_f << data.rdbuf();
384
385 // Close the file
386 out_f.close();
387 } else {
388 // Throw an exception if the file could not be opened for writing
390 "unimplemented case : could not open file " + fname + " for writing");
391 }
392 }
393 };
394
404 inline FortranIOFile load_fortran_file(const std::string &fname) {
405 std::ifstream in_f(fname, std::ios::binary);
406
407 std::basic_stringstream<byte> buffer;
408 if (in_f) {
409 buffer << in_f.rdbuf();
410 in_f.close();
411 } else {
412 throw_unimplemented("unimplemented case : file not found");
413 }
414
415 return FortranIOFile(std::move(buffer), buffer.tellp());
416 }
417
418} // namespace shambase
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
char byte
byte type similar to std::byte
std::int32_t i32
32 bit integer
Class for reading and writing Fortran-style binary files.
void write(Args &...args)
Write a list of arguments to the internal buffer.
void write_string_array(std::vector< std::string > &svec, u32 strlen, u32 str_count)
Write a fixed-length string array to the buffer.
void write_val_array(std::vector< T > &vec, u32 val_count)
Write an array of values to the buffer.
void read_fixed_string(std::string &s, u32 len)
Read a fixed-length string from the buffer.
int fort_int
Fortran int type.
void read(Args &...args)
Read a list of arguments from the internal buffer.
void read_string_array(std::vector< std::string > &svec, u32 strlen, u32 str_count)
Read a fixed-length string array from the buffer.
void read_val_array(std::vector< T > &vec, u32 val_count)
Read an array of values from the buffer.
void write_fixed_string(std::string &s, u32 len)
Write a fixed-length string to the buffer.
std::basic_stringstream< byte > & get_internal_buf()
Get a reference to the internal buffer.
f64 fort_real
Fortran real type.
FortranIOFile(std::basic_stringstream< byte > &&data_in, u64 length)
Construct a new FortranIOFile object.
bool finished_read()
Check if the end of the file has been reached.
void write_to_file(std::string fname)
Write the Fortran formatted file to disk.
This header file contains utility functions related to exception handling in the code.
namespace for basic c++ utilities
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
FortranIOFile load_fortran_file(const std::string &fname)
Load a Fortran formatted file from disk.
void throw_unimplemented(SourceLocation loc=SourceLocation{})
Throw a std::runtime_error saying that the function is unimplemented.
STL namespace.