LCOV - code coverage report
Current view: top level - src - filebuf.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 94 96 97.9 %
Date: 2019-01-29 11:06:41 Functions: 24 25 96.0 %

          Line data    Source code
       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         193 : 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          87 :         errorT Open(const char* filename, fileModeT fmode) {
      44          87 :                 std::ios::openmode mode = std::ios::binary;
      45          87 :                 switch (fmode) {
      46          33 :                 case FMODE_ReadOnly:
      47          33 :                         mode |= std::ios::in;
      48          33 :                         break;
      49          15 :                 case FMODE_WriteOnly:
      50          15 :                         mode |= std::ios::out;
      51          15 :                         break;
      52          15 :                 case FMODE_Both:
      53          15 :                         mode |= std::ios::in | std::ios::out;
      54          15 :                         break;
      55          20 :                 case FMODE_Create:
      56          20 :                         mode |= std::ios::in | std::ios::out | std::ios::trunc;
      57          20 :                         break;
      58           4 :                 default:
      59           4 :                         return ERROR_FileMode;
      60             :                 }
      61             : 
      62          83 :                 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         491 :         size_t getline(char* str, size_t count) {
      87         491 :                 ASSERT(str != 0);
      88         491 :                 ASSERT(count != 0);
      89             : 
      90         491 :                 size_t n = 0;
      91        9220 :                 for (int ch = sgetc(); ch != EOF; ch = snextc()) {
      92        9206 :                         ++n;
      93        9206 :                         if (ch == '\n') {
      94         217 :                                 sbumpc();
      95         217 :                                 break;
      96             :                         }
      97        8989 :                         if (n >= count) {
      98         260 :                                 n = 0; // Fail: buffer too small
      99         260 :                                 break;
     100             :                         }
     101        8729 :                         *str++ = static_cast<char>(ch);
     102             :                 }
     103         491 :                 *str = 0;
     104         491 :                 return n;
     105             :         }
     106             : 
     107             :         /**
     108             :          * Reads a 8-bit unsigned integer.
     109             :          * This function do not check for errors or EOF.
     110             :          */
     111      299025 :         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      134495 :         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        3081 :         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        3028 :         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      148910 :         int WriteOneByte(byte value) {
     136      148910 :                 int_type ch = sputc(static_cast<char_type>(value));
     137      148910 :                 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       66582 :         int WriteTwoBytes(uint32_t value) {
     145       66582 :                 return WriteOneByte(static_cast<byte>(value >> 8)) +
     146       66582 :                        WriteOneByte(static_cast<byte>(value));
     147             :         }
     148             :         /**
     149             :          * Writes a 24-bit unsigned integer.
     150             :          * @returns the number of characters successfully written.
     151             :          */
     152        2120 :         int WriteThreeBytes(uint32_t value) {
     153        4240 :                 return WriteOneByte(static_cast<byte>(value >> 16)) +
     154        2120 :                        WriteOneByte(static_cast<byte>(value >> 8)) +
     155        2120 :                        WriteOneByte(static_cast<byte>(value));
     156             :         }
     157             :         /**
     158             :          * Writes a 32-bit unsigned integer.
     159             :          * @returns the number of characters successfully written.
     160             :          */
     161        2027 :         int WriteFourBytes(uint32_t value) {
     162        4054 :                 return WriteOneByte(static_cast<byte>(value >> 24)) +
     163        4054 :                        WriteOneByte(static_cast<byte>(value >> 16)) +
     164        2027 :                        WriteOneByte(static_cast<byte>(value >> 8)) +
     165        2027 :                        WriteOneByte(static_cast<byte>(value));
     166             :         }
     167             : 
     168             : private:
     169      140604 :         template <int nBytes> uint32_t read() {
     170      140604 :                 uint32_t res = 0;
     171             :                 if (nBytes > 3)
     172        3028 :                         res += ReadOneByte() << 24;
     173             :                 if (nBytes > 2)
     174        6109 :                         res += ReadOneByte() << 16;
     175             :                 if (nBytes > 1)
     176      140604 :                         res += ReadOneByte() << 8;
     177      140604 :                 return res + ReadOneByte();
     178             :         }
     179             : };
     180             : 
     181             : /**
     182             :  * Optimizes std::filebuf for random-access reading.
     183             :  */
     184          22 : class FilebufAppend : protected Filebuf {
     185             :         std::streamoff fileSz_;
     186             :         std::streamoff filePos_;
     187             : 
     188             : public:
     189          22 :         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          21 :         errorT open(const std::string& filename, fileModeT fmode) {
     198          21 :                 errorT res = Open(filename.c_str(), fmode);
     199          21 :                 if (res != OK)
     200           1 :                         return res;
     201          20 :                 fileSz_ = pubseekoff(0, std::ios::end);
     202          20 :                 if (fileSz_ == -1)
     203           0 :                         return ERROR_FileSeek;
     204          20 :                 return OK;
     205             :         }
     206             : 
     207             :         /**
     208             :          * Returns the size of the file.
     209             :          */
     210       10030 :         unsigned long long 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           6 :         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        4805 :         errorT append(const char_type* s, std::streamsize count) {
     224        4805 :                 assert(s != 0);
     225             : 
     226        4805 :                 if (filePos_ != -2) { // Seek to end of file, if necessary.
     227          13 :                         filePos_ = seekpos(fileSz_);
     228          13 :                         if (filePos_ == -1)
     229           0 :                                 return ERROR_FileSeek;
     230          13 :                         filePos_ = -2;
     231             :                 }
     232             : 
     233        4805 :                 std::streamsize n = xsputn(s, count);
     234        4805 :                 fileSz_ += n;
     235        4805 :                 return (n == count) ? OK : ERROR_FileWrite;
     236             :         }
     237             : 
     238             :         /**
     239             :          * Invoke filebuf::xsgetn() and update @e filePos_.
     240             :          */
     241        6010 :         std::streamsize sgetn(char_type* s, std::streamsize count) {
     242        6010 :                 std::streamsize res = xsgetn(s, count);
     243        6010 :                 filePos_ += res;
     244        6010 :                 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        6010 :         std::streamoff pubseekpos(std::streamoff pos) {
     253        6010 :                 if (filePos_ < 0 || pos < filePos_)
     254        1022 :                         return filePos_ = seekpos(pos);
     255             : 
     256        4988 :                 if (filePos_ != pos) {
     257        1606 :                         const std::streamsize avail = egptr() - gptr();
     258        1606 :                         if (avail >= pos - filePos_) {
     259          40 :                                 ASSERT(pos - filePos_ <= INT_MAX);
     260          40 :                                 gbump(static_cast<int>(pos - filePos_));
     261          40 :                                 filePos_ = pos;
     262             :                         } else {
     263        1566 :                                 filePos_ = seekpos(pos);
     264             :                         }
     265             :                 }
     266        4988 :                 return filePos_;
     267             :         }
     268             : };
     269             : 
     270             : #endif // FILEBUF_H

Generated by: LCOV version 1.13