The Sparta Modeling Framework
Loading...
Searching...
No Matches
FILEStream.hpp
1// <FILEStream> -*- C++ -*-
2
3#pragma once
4
5#include <ios>
6#include <iostream>
7#include <memory>
8#include <algorithm>
9#include <cstdio>
10#include <cstring>
11
22
23private:
24
35 class OFILE_streambuf : public std::streambuf {
36 public:
37
46 OFILE_streambuf(FILE *fp, size_t buf_size = 1024) :
47 fp_(fp),
48 buf_(new char[buf_size]),
49 buf_size_(buf_size)
50 {
51 if (fp_ == nullptr) {
52 throw std::ios_base::failure("Underlying stream pointer is null");
53 }
54 if (buf_.get() == nullptr) {
55 throw std::bad_alloc();
56 }
57
58 char *b = buf_.get();
59
60 // Set current pointer to beginning of buffer
61 setp(&b[0], &b[buf_size_]);
62 }
63
64 private:
65
74 int_type overflow(int_type ch = traits_type::eof()) override {
75
76 // Try to drain the intermediate buffer, if it is full.
77 if (pptr() == epptr()) {
78 sync();
79 }
80 if (traits_type::eq_int_type(ch, traits_type::eof()) == true) {
81 return traits_type::eof();
82 }
83
84 // Insert the new character into the intermediate buffer.
85 // Note: the pptr() may still be epptr(), if sync failed above.
86 if (pptr() != epptr()) {
87 *pptr() = ch;
88 pbump(1);
89 return 0;
90 }
91 return traits_type::eof();
92 }
93
98 int sync() override {
99 size_t chars_to_write = pptr() - pbase();
100 size_t chars_written = fwrite(pbase(), 1, chars_to_write, fp_);
101 if (chars_written == chars_to_write) {
102 char *b = buf_.get();
103 setp(&b[0], &b[buf_size_]);
104 return 0;
105 }
106 pbump(chars_written);
107 return -1;
108 }
109
117 std::streamsize xsputn(const char_type *s, std::streamsize count) override {
118 // First flush out the intermediate buffer
119 if (sync() == -1) {
120 return 0;
121 }
122
123 // Now write the rest of the characters directly to the FILE
124 return fwrite(s, 1, count, fp_);
125 }
126
127 FILE *fp_;
128 std::unique_ptr<char[]> buf_;
129 const size_t buf_size_;
130 };
131
132public:
133
138 FILEOstream(FILE *fd) :
139 streambuf_(fd),
140 stream_(&streambuf_) { }
141
148 std::ostream& getStream() {
149 return stream_;
150 }
151
152private:
153
154 OFILE_streambuf streambuf_;
155 std::ostream stream_;
156};
157
158
169
170private:
171
188 class IFILE_streambuf : public std::streambuf {
189 public:
190
199 IFILE_streambuf(FILE *fp, size_t buf_size = 1024) :
200 fp_(fp),
201 buf_(new char[buf_size]),
202 buf_size_(buf_size)
203 {
204 if (fp_ == nullptr) {
205 throw std::ios_base::failure("Underlying stream pointer is null");
206 }
207 if (buf_.get() == nullptr) {
208 throw std::bad_alloc();
209 }
210
211 char *b = buf_.get();
212
213 // Set current pointer to end of buffer, indicating it is empty
214 setg(&b[0], &b[buf_size_], &b[buf_size_]);
215 }
216
217 private:
218
227 int_type underflow() override {
228 if (gptr() == egptr()) {
229 char *b = buf_.get();
230 auto byte_cnt = xsgetn(b, buf_size_);
231 if (byte_cnt == 0) {
232 // There is no more data from the file, and the
233 // intermediate buffer is empty. Leave gptr() == egptr(),
234 // as required by parent class.
235 return traits_type::eof();
236
237 } else if (static_cast<size_t>(byte_cnt) < buf_size_) {
238 // We just extracted the last of the data from the file,
239 // and the intermediate buffer is partially filled. Set
240 // the end pointer accordingly.
241 setg(&b[0], &b[0], &b[byte_cnt]);
242
243 } else {
244 // We just filled the entire intermediate buffer, and there
245 // is still more data to read from the file.
246 setg(&b[0], &b[0], &b[buf_size_]);
247 }
248 }
249 return *gptr();
250 }
251
259 std::streamsize xsgetn(char *s, std::streamsize count) override {
260 // First empty the intermediate buffer.
261 size_t intermediate_chars = egptr() - gptr();
262 size_t intermediate_copy = std::min(intermediate_chars, static_cast<size_t>(count));
263 memcpy(s, gptr(), intermediate_copy);
264 gbump(intermediate_copy); // Advance gptr()
265 s += intermediate_copy;
266 count -= intermediate_copy;
267 size_t retval = intermediate_copy;
268
269 // Now directly read from the FILE for the rest.
270 retval += fread(s, 1, count, fp_);
271 return retval;
272 }
273
274 FILE *fp_;
275 std::unique_ptr<char[]> buf_;
276 const size_t buf_size_;
277 };
278
279public:
280
285 FILEIstream(FILE *fd) :
286 streambuf_(fd),
287 stream_(&streambuf_) { }
288
295 std::istream& getStream() {
296 return stream_;
297 }
298
299private:
300
301 IFILE_streambuf streambuf_;
302 std::istream stream_;
303};
304
305
std::istream & getStream()
FILEIstream(FILE *fd)
FILEOstream(FILE *fd)
std::ostream & getStream()