A library for working with phylogenetic and population genetic data.
v0.32.0
file_input_source.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_IO_FILE_INPUT_SOURCE_H_
2 #define GENESIS_UTILS_IO_FILE_INPUT_SOURCE_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2022 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lczech@carnegiescience.edu>
23  Department of Plant Biology, Carnegie Institution For Science
24  260 Panama Street, Stanford, CA 94305, USA
25 */
26 
36 
37 #include <cassert>
38 #include <cerrno>
39 #include <cstdio>
40 #include <cstring>
41 #include <istream>
42 #include <stdexcept>
43 #include <string>
44 
45 namespace genesis {
46 namespace utils {
47 
48 // =================================================================================================
49 // File Input Source
50 // =================================================================================================
51 
60 class FileInputSource final : public BaseInputSource
61 {
62 public:
63 
64  // -------------------------------------------------------------
65  // Constructors and Rule of Five
66  // -------------------------------------------------------------
67 
71  explicit FileInputSource( std::string const& file_name )
72  : file_name_( file_name )
73  {
74  std::string err_str;
75  if( ! file_is_readable( file_name )) {
76  throw std::runtime_error(
77  "Cannot open input file '" + file_name + "': " + err_str
78  );
79  }
80  }
81 
86  explicit FileInputSource( std::string const& file_name, FILE* file )
87  : file_( file )
88  , file_name_( file_name )
89  {
90  // We do our own buffering.
91  std::setvbuf( file_, nullptr, _IONBF, 0 );
92  }
93 
94  FileInputSource( FileInputSource const& ) = default;
95  FileInputSource( FileInputSource&& ) = default;
96 
97  FileInputSource& operator= ( FileInputSource const& ) = default;
99 
100  ~FileInputSource() override
101  {
102  // It might already be closed,
103  // but in case of aborting before the end of the file, it might not.
104  if( file_ ) {
105  std::fclose( file_ );
106  }
107  }
108 
109  // -------------------------------------------------------------
110  // Overloaded Internal Members
111  // -------------------------------------------------------------
112 
113 private:
114 
118  size_t read_( char* buffer, size_t size ) override
119  {
120  // Special case: we already finished reading the file.
121  // We need this check as otherwise the file would be reopened again and
122  // read again from the start.
123  if( finished_ ) {
124  return 0;
125  }
126 
127  // We need to do lazy loading, otherwise, we might end up having too many open files
128  // if we are using the from_files() function, which opens all files at once...
129  if( file_ == nullptr ) {
130  errno = 0;
131  file_ = std::fopen( file_name_.c_str(), "rb" );
132 
133  if( file_ == nullptr ) {
134  throw std::runtime_error(
135  "Cannot open input file '" + file_name_ + "': " +
136  std::string( strerror( errno ))
137  );
138  }
139 
140  // We do our own buffering.
141  std::setvbuf( file_, nullptr, _IONBF, 0 );
142  }
143 
144  // Do the reading.
145  errno = 0;
146  size_t const ret = std::fread( buffer, 1, size, file_ );
147  if( std::ferror( file_ ) ) {
148  assert( ! std::feof( file_ ));
149  throw std::runtime_error(
150  "Cannot read from input file '" + file_name_ + "': " +
151  std::string( strerror( errno ))
152  );
153  }
154 
155  // Similarly, we need to close again once we are done, so that the file is not kept
156  // open unnecessarily long after reading.
157  if( ret < size ) {
158  assert( std::feof( file_ ));
159  assert( !std::ferror( file_ ));
160  std::fclose( file_ );
161  file_ = nullptr;
162  finished_ = true;
163  }
164 
165  return ret;
166  }
167 
171  std::string source_name_() const override
172  {
173  return "input file (" + file_name_ + ")";
174  }
175 
179  std::string source_string_() const override
180  {
181  return file_name_;
182  }
183 
184  // -------------------------------------------------------------
185  // Member Variables
186  // -------------------------------------------------------------
187 
188  FILE* file_ = nullptr;
189  std::string file_name_;
190  bool finished_ = false;
191 };
192 
193 } // namespace utils
194 } // namespace genesis
195 
196 #endif // include guard
fs.hpp
Provides functions for accessing the file system.
genesis::utils::FileInputSource::FileInputSource
FileInputSource(std::string const &file_name)
Construct the input source from a file with the given file name.
Definition: file_input_source.hpp:71
base_input_source.hpp
genesis::utils::FileInputSource
Input source for reading byte data from a file.
Definition: file_input_source.hpp:60
genesis::utils::FileInputSource::FileInputSource
FileInputSource(std::string const &file_name, FILE *file)
Construct the input source from a FILE pointer. The file_name is used for the source_name() function ...
Definition: file_input_source.hpp:86
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::file_is_readable
bool file_is_readable(std::string const &filename)
Return whether a file is readable.
Definition: fs.cpp:108
genesis::utils::FileInputSource::operator=
FileInputSource & operator=(FileInputSource const &)=default
genesis::utils::BaseInputSource
Abstract base class for reading byte data from input sources.
Definition: base_input_source.hpp:50
genesis::utils::FileInputSource::~FileInputSource
~FileInputSource() override
Definition: file_input_source.hpp:100