xerus
a general purpose tensor library
fileIO.h
Go to the documentation of this file.
1 // Xerus - A General Purpose Tensor Library
2 // Copyright (C) 2014-2017 Benjamin Huber and Sebastian Wolf.
3 //
4 // Xerus is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as published
6 // by the Free Software Foundation, either version 3 of the License,
7 // or (at your option) any later version.
8 //
9 // Xerus is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
13 //
14 // You should have received a copy of the GNU Affero General Public License
15 // along with Xerus. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // For further information on Xerus visit https://libXerus.org
18 // or contact us at contact@libXerus.org.
19 
26 #pragma once
27 
28 #include <iostream>
29 #include <fstream>
30 #include "stringUtilities.h"
31 #include "check.h"
32 #include "exceptions.h"
33 #include "namedLogger.h"
34 
35 namespace xerus { namespace misc {
36 
43  enum class FileFormat { BINARY, TSV };
44 
45  // ---------------------------------------- write_to_stream -------------------------------------------------------------
46  template<class T>
47  XERUS_force_inline void write_to_stream(std::ostream& _stream, const T &_value, FileFormat _format) {
48  stream_writer(_stream, _value, _format);
49  }
50 
51  template<class T, typename std::enable_if<std::is_arithmetic<T>::value, bool>::type = true>
52  void stream_writer(std::ostream& _stream, const T &_value, FileFormat _format) {
53  if (_format == FileFormat::TSV) {
54  _stream << _value << '\t';
55  } else {
56  _stream.write(reinterpret_cast<const char*>(&_value), std::streamsize(sizeof(T)));
57  }
58  }
59 
60  template<class T>
61  void stream_writer(std::ostream& _stream, const std::vector<T> &_value, FileFormat _format) {
62  write_to_stream<size_t>(_stream, _value.size(), _format);
63  for (size_t i = 0; i < _value.size(); ++i) {
64  write_to_stream<T>(_stream, _value[i], _format);
65  }
66  }
67 
68 
69  // ---------------------------------------- read_from_stream -------------------------------------------------------------
70  template<class T>
71  XERUS_force_inline void read_from_stream(std::istream& _stream, T &_obj, const FileFormat _format) {
72  stream_reader(_stream, _obj, _format);
73  }
74 
75  template<class T>
76  XERUS_force_inline T read_from_stream(std::istream& _stream, const FileFormat _format) {
77  T obj;
78  stream_reader(_stream, obj, _format);
79  return obj;
80  }
81 
82  template<class T, typename std::enable_if<std::is_arithmetic<T>::value, bool>::type = true>
83  void stream_reader(std::istream& _stream, T &_obj, const FileFormat _format) {
84  if(_format == FileFormat::TSV) {
85  _stream >> _obj;
86  } else {
87  _stream.read(reinterpret_cast<char*>(&_obj), sizeof(T));
88  }
89  }
90 
91  template<class T>
92  void stream_reader(std::istream& _stream, std::vector<T> &_obj, const FileFormat _format) {
93  _obj.resize(read_from_stream<size_t>(_stream, _format));
94  for (size_t i = 0; i < _obj.size(); ++i) {
95  read_from_stream<T>(_stream, _obj[i], _format);
96  }
97  }
98 
99  // ---------------------------------------- save / load file -------------------------------------------------------------
100 
101 
102  template<class T>
103  void save_to_file(const T &_obj, const std::string &_filename, const FileFormat _format = FileFormat::BINARY) {
104  try {
105  if (_format == FileFormat::BINARY) {
106  std::ofstream out(_filename, std::ofstream::out | std::ofstream::binary);
107  std::string header = std::string("Xerus ") + misc::demangle_cxa(typeid(T).name()) + " datafile.\nFormat: Binary\n";
108  out.write(header.c_str(), std::streamsize(header.size()));
109  write_to_stream<T>(out, _obj, _format);
110  } else {
111  std::ofstream out(_filename, std::ofstream::out);
112  out << std::string("Xerus ") << misc::demangle_cxa(typeid(T).name()) << " datafile.\nFormat: TSV\n";
113  write_to_stream<T>(out, _obj, _format);
114  }
115  } catch (generic_error &e) {
116  throw e << "error occured while writing to file " << _filename << '\n';
117  }
118  }
119 
120 
121  template<class T>
122  void load_from_file(T &_obj, const std::string& _filename) {
123  try {
124  std::ifstream in(_filename, std::ifstream::in);
125 
126  std::string firstLine;
127  std::getline(in, firstLine);
128 
129  XERUS_REQUIRE(in, "Unexpected end of stream in load_from_file().");
130 
131  XERUS_REQUIRE(firstLine == std::string("Xerus ") + misc::demangle_cxa(typeid(T).name()) + " datafile.", "Invalid binary input file " << _filename << ". DBG: " << firstLine);
132 
133  std::string formatQual, formatValue;
134  in >> formatQual >> formatValue;
135 
136  XERUS_REQUIRE(formatQual == std::string("Format:"), "Invalid Sytax detected in file " << _filename << ". DBG: " << formatQual);
137 
138  FileFormat format;
139  if(formatValue == std::string("TSV")) {
140  format = FileFormat::TSV;
141  } else if(formatValue == std::string("Binary")) {
142  format = FileFormat::BINARY;
143 
144  // Open the stream as binary and skip to the start of the binary part.
145  const std::streamoff currPos = in.tellg();
146  in.close();
147  in.open(_filename, std::ifstream::in | std::ifstream::binary);
148  in.seekg(currPos+1); // +1 because of the last \n
149  } else {
150  XERUS_LOG(fatal, "Invalid value for format detected. " << formatValue);
151  }
152 
153  read_from_stream<T>(in, _obj, format);
154  } catch (generic_error &e) {
155  throw e << "error occured in file " << _filename << '\n';
156  }
157  }
158 
159  template<class T>
160  T load_from_file(const std::string& _filename) {
161  T result;
162  load_from_file<T>(result, _filename);
163  return result;
164  }
165 
166 }}
Header file for CHECK and REQUIRE macros.
void stream_reader(std::istream &_stream, Tensor &_obj, const FileFormat _format)
tries to restore the tensor from a stream of data.
Definition: tensor.cpp:1807
The main namespace of xerus.
Definition: basic.h:37
void load_from_file(T &_obj, const std::string &_filename)
Definition: fileIO.h:122
XERUS_force_inline void read_from_stream(std::istream &_stream, T &_obj, const FileFormat _format)
Definition: fileIO.h:71
FileFormat
possible file formats for tensor storage
Definition: fileIO.h:43
The xerus exception class.
Definition: exceptions.h:37
Header file for xerus::misc::generic_error exception class.
Header file for all logging macros and log-buffer functionality.
#define XERUS_LOG(lvl,...)
logs the message msg with severity level lvl
Definition: namedLogger.h:139
void save_to_file(const T &_obj, const std::string &_filename, const FileFormat _format=FileFormat::BINARY)
Definition: fileIO.h:103
#define XERUS_REQUIRE(condition, message)
Checks whether condition is true. logs an error otherwise via XERUS_LOG(error, message).
Definition: check.h:65
Header file for some elementary string manipulation routines.
XERUS_force_inline void write_to_stream(std::ostream &_stream, const T &_value, FileFormat _format)
Definition: fileIO.h:47
void stream_writer(std::ostream &_stream, const Tensor &_obj, const FileFormat _format)
pipes all information necessary to restore the current tensor into _stream.
Definition: tensor.cpp:1781
std::string XERUS_warn_unused demangle_cxa(const std::string &_cxa)
Demangles the function and class names created by gcc into a more readable format.
#define XERUS_force_inline
Collection of attributes to force gcc to inline a specific function.
Definition: standard.h:75