Scid  4.6.5
filebuf.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014-2017 Fulvio Benini
3 
4  * This file is part of Scid (Shane's Chess Information Database).
5  *
6  * Scid is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Scid is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /** @file
20  * Extends the std:filebuf class with performance improvements.
21  */
22 
23 #ifndef FILEBUF_H
24 #define FILEBUF_H
25 
26 #include "common.h"
27 #include <climits>
28 #include <fstream>
29 
30 /**
31  * Adds some helper functions to std::filebuf:
32  * - getline()
33  * - read and write of unsigned integers with size of 32/24/16/8 bit.
34  */
35 class Filebuf : public std::filebuf {
36 public:
37  /**
38  * Opens a file.
39  * @param filename: path to the file to be opened.
40  * @param fmode: open the file for reading, writing, or both.
41  * @returns OK on success, an @e errorT code on failure.
42  */
43  errorT Open(const char* filename, fileModeT fmode) {
44  std::ios::openmode mode = std::ios::binary;
45  switch (fmode) {
46  case FMODE_ReadOnly:
47  mode |= std::ios::in;
48  break;
49  case FMODE_WriteOnly:
50  mode |= std::ios::out;
51  break;
52  case FMODE_Both:
53  mode |= std::ios::in | std::ios::out;
54  break;
55  case FMODE_Create:
56  mode |= std::ios::in | std::ios::out | std::ios::trunc;
57  break;
58  default:
59  return ERROR_FileMode;
60  }
61 
62  return (open(filename, mode) != 0) ? OK : ERROR_FileOpen;
63  }
64 
65  /**
66  * Equivalent to std::fstream::getline, but faster (no sentry [27.7.2.1.3]).
67  *
68  * Extracts characters from @e *this and stores them in successive locations
69  * of the array whose first element is pointed to by @p str, until the end
70  * of line ('\\n' char) or the end of file condition occurs.
71  * The '\\n' char is not stored into @p str, and a null character, even in
72  * case of errors, is appended.
73  *
74  * Typical usage: @code
75  * while (file.getline(buf, sizeof buf)) {
76  * // use buf
77  * }
78  * if (file.sgetc() != EOF) // error
79  * @endcode
80  * @param str: pointer to the character string to store the characters to
81  * @param count: size of character string pointed to by @p str
82  * @returns
83  * - the number of characters read, including the '\\n' char
84  * - 0 on failure or if the buffer is too small.
85  */
86  size_t getline(char* str, size_t count) {
87  ASSERT(str != 0);
88  ASSERT(count != 0);
89 
90  size_t n = 0;
91  for (int ch = sgetc(); ch != EOF; ch = snextc()) {
92  ++n;
93  if (ch == '\n') {
94  sbumpc();
95  break;
96  }
97  if (n >= count) {
98  n = 0; // Fail: buffer too small
99  break;
100  }
101  *str++ = static_cast<char>(ch);
102  }
103  *str = 0;
104  return n;
105  }
106 
107  /**
108  * Reads a 8-bit unsigned integer.
109  * This function do not check for errors or EOF.
110  */
111  byte ReadOneByte() { return static_cast<byte>(sbumpc()); }
112 
113  /**
114  * Reads a 16-bit unsigned integer.
115  * This function do not check for errors or EOF.
116  */
117  uint16_t ReadTwoBytes() { return static_cast<uint16_t>(read<2>()); }
118 
119  /**
120  * Reads a 24-bit unsigned integer.
121  * This function do not check for errors or EOF.
122  */
123  uint32_t ReadThreeBytes() { return read<3>(); }
124 
125  /**
126  * Reads a 32-bit unsigned integer.
127  * This function do not check for errors or EOF.
128  */
129  uint32_t ReadFourBytes() { return read<4>(); }
130 
131  /**
132  * Writes a 8-bit unsigned integer.
133  * @returns the number of characters successfully written.
134  */
135  int WriteOneByte(byte value) {
136  int_type ch = sputc(static_cast<char_type>(value));
137  return (ch != traits_type::eof()) ? 1 : 0;
138  }
139 
140  /**
141  * Writes a 16-bit unsigned integer.
142  * @returns the number of characters successfully written.
143  */
144  int WriteTwoBytes(uint32_t value) {
145  return WriteOneByte(static_cast<byte>(value >> 8)) +
146  WriteOneByte(static_cast<byte>(value));
147  }
148  /**
149  * Writes a 24-bit unsigned integer.
150  * @returns the number of characters successfully written.
151  */
152  int WriteThreeBytes(uint32_t value) {
153  return WriteOneByte(static_cast<byte>(value >> 16)) +
154  WriteOneByte(static_cast<byte>(value >> 8)) +
155  WriteOneByte(static_cast<byte>(value));
156  }
157  /**
158  * Writes a 32-bit unsigned integer.
159  * @returns the number of characters successfully written.
160  */
161  int WriteFourBytes(uint32_t value) {
162  return WriteOneByte(static_cast<byte>(value >> 24)) +
163  WriteOneByte(static_cast<byte>(value >> 16)) +
164  WriteOneByte(static_cast<byte>(value >> 8)) +
165  WriteOneByte(static_cast<byte>(value));
166  }
167 
168 private:
169  template <int nBytes> uint32_t read() {
170  uint32_t res = 0;
171  if (nBytes > 3)
172  res += ReadOneByte() << 24;
173  if (nBytes > 2)
174  res += ReadOneByte() << 16;
175  if (nBytes > 1)
176  res += ReadOneByte() << 8;
177  return res + ReadOneByte();
178  }
179 };
180 
181 /**
182  * Optimizes std::filebuf for random-access reading.
183  */
184 class FilebufAppend : protected Filebuf {
185  std::streamoff fileSz_;
186  std::streamoff filePos_;
187 
188 public:
189  FilebufAppend() : fileSz_(0), filePos_(-1) {}
190 
191  /**
192  * Opens a file and store its size.
193  * @param filename: path to the file to be opened.
194  * @param fmode: open the file for reading, writing, or both.
195  * @returns OK on success, an @e errorT code on failure.
196  */
197  errorT open(const std::string& filename, fileModeT fmode) {
198  errorT res = Open(filename.c_str(), fmode);
199  if (res != OK)
200  return res;
201  fileSz_ = pubseekoff(0, std::ios::end);
202  if (fileSz_ == -1)
203  return ERROR_FileSeek;
204  return OK;
205  }
206 
207  /**
208  * Returns the size of the file.
209  */
210  size_t size() const { return fileSz_; }
211 
212  /**
213  * Invokes std::filebuf::sync() to write all pending output to the file.
214  * @returns 0 in case of success, -1 in case of failure.
215  */
216  int pubsync() { return sync(); }
217 
218  /**
219  * Writes, at the end of the file, @p count characters from the character
220  * array whose first element is pointed to by @p s.
221  * @returns OK in case of success, an error code otherwise.
222  */
223  errorT append(const char_type* s, std::streamsize count) {
224  assert(s != 0);
225 
226  if (filePos_ != -2) { // Seek to end of file, if necessary.
227  filePos_ = seekpos(fileSz_);
228  if (filePos_ == -1)
229  return ERROR_FileSeek;
230  filePos_ = -2;
231  }
232 
233  std::streamsize n = xsputn(s, count);
234  fileSz_ += n;
235  return (n == count) ? OK : ERROR_FileWrite;
236  }
237 
238  /**
239  * Invoke filebuf::xsgetn() and update @e filePos_.
240  */
241  std::streamsize sgetn(char_type* s, std::streamsize count) {
242  std::streamsize res = xsgetn(s, count);
243  filePos_ += res;
244  return res;
245  }
246 
247  /**
248  * Repositions the internal buffer or invoke filebuf::seekpos().
249  * In the standard implementation, the buffer must be abandoned to ensure
250  * consistency when transitioning from reading to writing.
251  */
252  std::streamoff pubseekpos(std::streamoff pos) {
253  if (filePos_ < 0 || pos < filePos_)
254  return filePos_ = seekpos(pos);
255 
256  if (filePos_ != pos) {
257  const std::streamsize avail = egptr() - gptr();
258  if (avail >= pos - filePos_) {
259  ASSERT(pos - filePos_ <= INT_MAX);
260  gbump(static_cast<int>(pos - filePos_));
261  filePos_ = pos;
262  } else {
263  filePos_ = seekpos(pos);
264  }
265  }
266  return filePos_;
267  }
268 };
269 
270 #endif // FILEBUF_H
unsigned char byte
Definition: common.h:97
errorT append(const char_type *s, std::streamsize count)
Writes, at the end of the file, count characters from the character array whose first element is poin...
Definition: filebuf.h:223
int WriteFourBytes(uint32_t value)
Writes a 32-bit unsigned integer.
Definition: filebuf.h:161
std::streamoff pubseekpos(std::streamoff pos)
Repositions the internal buffer or invoke filebuf::seekpos().
Definition: filebuf.h:252
const errorT OK
Definition: error.h:23
const errorT ERROR_FileWrite
Definition: error.h:32
int WriteOneByte(byte value)
Writes a 8-bit unsigned integer.
Definition: filebuf.h:135
#define ASSERT(f)
Definition: common.h:67
errorT open(const std::string &filename, fileModeT fmode)
Opens a file and store its size.
Definition: filebuf.h:197
uint16_t ReadTwoBytes()
Reads a 16-bit unsigned integer.
Definition: filebuf.h:117
int WriteThreeBytes(uint32_t value)
Writes a 24-bit unsigned integer.
Definition: filebuf.h:152
size_t size() const
Returns the size of the file.
Definition: filebuf.h:210
int WriteTwoBytes(uint32_t value)
Writes a 16-bit unsigned integer.
Definition: filebuf.h:144
uint32_t ReadThreeBytes()
Reads a 24-bit unsigned integer.
Definition: filebuf.h:123
int pubsync()
Invokes std::filebuf::sync() to write all pending output to the file.
Definition: filebuf.h:216
open?name?
Definition: book.tcl:89
errorT Open(const char *filename, fileModeT fmode)
Opens a file.
Definition: filebuf.h:43
byte ReadOneByte()
Reads a 8-bit unsigned integer.
Definition: filebuf.h:111
unsigned short errorT
Definition: error.h:20
const errorT ERROR_FileSeek
Definition: error.h:34
Optimizes std::filebuf for random-access reading.
Definition: filebuf.h:184
std::streamsize sgetn(char_type *s, std::streamsize count)
Invoke filebuf::xsgetn() and update filePos_.
Definition: filebuf.h:241
Adds some helper functions to std::filebuf:
Definition: filebuf.h:35
uint32_t ReadFourBytes()
Reads a 32-bit unsigned integer.
Definition: filebuf.h:129
fileModeT
Definition: common.h:144
const errorT ERROR_FileMode
Definition: error.h:38
const errorT ERROR_FileOpen
Definition: error.h:31
size_t getline(char *str, size_t count)
Equivalent to std::fstream::getline, but faster (no sentry [27.7.2.1.3]).
Definition: filebuf.h:86