LCOV - code coverage report
Current view: top level - snapdev - memory_streambuf.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 65 65
Test Date: 2026-02-16 17:48:13 Functions: 100.0 % 5 5
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2019-2026  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snapdev
       4              : // contact@m2osw.com
       5              : //
       6              : // This program 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, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : #pragma once
      19              : 
      20              : /** \file
      21              :  * \brief Create a stream from a memory buffer.
      22              :  *
      23              :  * At times we have a memory buffer that we need to pass as a stream.
      24              :  * This template can be used to transform that buffer in a streambuf,
      25              :  * which can then be passed to a stream on creation or through rdbuf().
      26              :  */
      27              : 
      28              : // snapdev
      29              : //
      30              : #include    <snapdev/not_reached.h>
      31              : #include    <snapdev/not_used.h>
      32              : 
      33              : 
      34              : // C++
      35              : //
      36              : #include    <iostream>
      37              : #include    <ostream>
      38              : //#include    <sstream>
      39              : //#include    <string>
      40              : 
      41              : 
      42              : 
      43              : namespace snapdev
      44              : {
      45              : 
      46              : 
      47              : 
      48              : /** \brief Create a streambuf where the data comes from a memory buffer.
      49              :  *
      50              :  * This class is used to create a streambuf from a memory buffer.
      51              :  * If you are looking at capturing the output of a stream, you may be
      52              :  * interested by the ostream_to_buf instead. That other implementation
      53              :  * allows you to save the output of a stream in a string and then verify
      54              :  * that string.
      55              :  *
      56              :  * This implementation was created for input rather than output, allowing
      57              :  * you to create a buffer from a memory buffer.
      58              :  *
      59              :  * \code
      60              :  * {
      61              :  *     // Say you have a vector with data
      62              :  *     char data[]{ 1, 2, 3, 4, 5, 6, 7 };
      63              :  *
      64              :  *     // you create a vector_streambuf this way
      65              :  *     snapdev::memory_streambuf buf(data, sizeof(data));
      66              :  *
      67              :  *     // and then an input stream this way
      68              :  *     std::istream in(&buf);
      69              :  *
      70              :  *     // now you can read & seek as usual
      71              :  *
      72              :  *     // if you want to be able to do updates, use an iostream insead
      73              :  *     std::iostream in_out(&buf);
      74              :  * }
      75              :  * \endcode
      76              :  *
      77              :  * \note
      78              :  * The function expects the memory buffer to only contain data that can
      79              :  * be read/written as such. This means no pointers, not classes with
      80              :  * virtual functions, etc.
      81              :  *
      82              :  * \warning
      83              :  * The memory buffer must remain available and not change in size.
      84              :  *
      85              :  * \tparam CharT  The type of characters used by the stream.
      86              :  * \tparam Traits  The traits of the specified character type.
      87              :  */
      88              : template<
      89              :       typename CharT = char
      90              :     , typename Traits = std::char_traits<CharT>
      91              : > class memory_streambuf
      92              :     : public std::basic_streambuf<CharT, Traits>
      93              : {
      94              : public:
      95              :     typedef CharT                       char_type;
      96              :     typedef Traits                      traits_type;
      97              :     typedef typename Traits::int_type   int_type;
      98              :     typedef typename Traits::pos_type   pos_type;
      99              :     typedef typename Traits::off_type   off_type;
     100              : 
     101              :     typedef std::basic_streambuf<char_type, traits_type>    streambuf_type;
     102              : 
     103              :     /** \brief Initialize the streambuf from \p data.
     104              :      *
     105              :      * This function creates a streambuf that you can then use to initialize
     106              :      * an input or output stream with.
     107              :      *
     108              :      * This version of the constructor allows to read and write to the
     109              :      * stream buffer (a.k.a. the vector). You can use it with input or
     110              :      * an output stream.
     111              :      *
     112              :      * Note that the reading and writing happen from the start of the
     113              :      * buffer unless a corresponding seek is used.
     114              :      *
     115              :      * \todo
     116              :      * Note that the overflow() function does not yet know how to grow
     117              :      * the vector. If you attempt to write past the end, an exception
     118              :      * is generated.
     119              :      *
     120              :      * \param[in] data  A pointer to a memory buffer.
     121              :      * \param[in] size  The size of the data buffer in bytes.
     122              :      */
     123            2 :     memory_streambuf(void * data, std::size_t size)
     124            2 :     {
     125            2 :         char * ptr(reinterpret_cast<char *>(data));
     126            2 :         char_type * begin(reinterpret_cast<char_type *>(ptr));
     127            2 :         char_type * end(reinterpret_cast<char_type *>(ptr + size));
     128            2 :         this->setg(begin, begin, end);
     129            2 :         this->setp(begin, end);
     130            2 :     }
     131              : 
     132              :     /** \brief Initialize the streambuf from \p vec.
     133              :      *
     134              :      * This function creates a read-only streambuf that you can then use
     135              :      * to initialize an input stream with. Trying to write to that stream
     136              :      * generates an exception.
     137              :      *
     138              :      * \param[in] data  A pointer to a memory buffer.
     139              :      * \param[in] size  The size of the data buffer in bytes.
     140              :      */
     141            1 :     memory_streambuf(void const * data, std::size_t size)
     142            1 :         : f_read_only(true)
     143              :     {
     144            1 :         char * ptr(const_cast<char *>(reinterpret_cast<char const *>(data)));
     145            1 :         char_type * begin(reinterpret_cast<char_type *>(ptr));
     146            1 :         char_type * end(reinterpret_cast<char_type *>(ptr + size));
     147            1 :         this->setg(begin, begin, end);
     148              : 
     149              :         // a write calls overflow() if the start & end pointers are the same
     150              :         //
     151            1 :         this->setp(begin, begin);
     152            1 :     }
     153              : 
     154              : protected:
     155              :     /** \brief Function called when an overflow on a put() happens.
     156              :      *
     157              :      * This function is called if a put() attempts to write past the
     158              :      * end of the buffer. In that case, we throw an exception. It is
     159              :      * not possible for us to grow the buffer.
     160              :      *
     161              :      * \param[in] c  The character to output.
     162              :      *
     163              :      * \return The input character \p c or '\0' of \p c is EOF.
     164              :      */
     165            3 :     int_type overflow(int_type c)
     166              :     {
     167            3 :         snapdev::NOT_USED(c);
     168            3 :         throw std::ios_base::failure("this buffer is read-only, writing to the buffer is not available.");
     169              :         snapdev::NOT_REACHED();
     170              :     }
     171              : 
     172           45 :     virtual pos_type seekoff(
     173              :           off_type const offset
     174              :         , std::ios_base::seekdir const dir
     175              :         , std::ios_base::openmode const mode) override
     176              :     {
     177           45 :         off_type result(-1);
     178              : 
     179           45 :         if((mode & std::ios_base::in) != 0)
     180              :         {
     181           32 :             char_type * pos = nullptr;
     182           32 :             switch(dir)
     183              :             {
     184           24 :             case std::ios_base::cur:
     185           24 :                 pos = this->gptr() + offset;
     186           24 :                 break;
     187              : 
     188            1 :             case std::ios_base::end:
     189            1 :                 pos = this->egptr() + offset;
     190            1 :                 break;
     191              : 
     192            6 :             case std::ios_base::beg:
     193            6 :                 pos = this->eback() + offset;
     194            6 :                 break;
     195              : 
     196            1 :             default:
     197            1 :                 throw std::ios_base::failure("unknown direction in seekoff() -- in");
     198              : 
     199              :             }
     200           31 :             if(pos < this->eback())
     201              :             {
     202            1 :                 pos = this->eback();
     203              :             }
     204           31 :             if(pos > this->egptr())
     205              :             {
     206            1 :                 pos = this->egptr();
     207              :             }
     208           31 :             this->setg(this->eback(), pos, this->egptr());
     209           31 :             result = pos - this->eback();
     210              :         }
     211              : 
     212           44 :         if((mode & std::ios_base::out) != 0)
     213              :         {
     214           13 :             char_type * pos = nullptr;
     215           13 :             switch(dir)
     216              :             {
     217            7 :             case std::ios_base::cur:
     218            7 :                 pos = this->pptr() + offset;
     219            7 :                 break;
     220              : 
     221            1 :             case std::ios_base::end:
     222            1 :                 pos = this->epptr() + offset;
     223            1 :                 break;
     224              : 
     225            4 :             case std::ios_base::beg:
     226            4 :                 pos = this->pbase() + offset;
     227            4 :                 break;
     228              : 
     229            1 :             default:
     230            1 :                 throw std::ios_base::failure("unknown direction in seekoff() -- out");
     231              : 
     232              :             }
     233           12 :             if(pos < this->pbase())
     234              :             {
     235            1 :                 pos = this->pbase();
     236              :             }
     237           12 :             if(pos > this->epptr())
     238              :             {
     239            2 :                 pos = this->epptr();
     240              :             }
     241           12 :             this->setp(this->pbase(), this->epptr());
     242           12 :             result = pos - this->pbase();
     243           12 :             this->pbump(result);
     244              :         }
     245              : 
     246           86 :         return result;
     247              :     }
     248              : 
     249           10 :     virtual pos_type seekpos(pos_type offset, std::ios_base::openmode mode) override
     250              :     {
     251           10 :         return seekoff(offset, std::ios_base::beg, mode);
     252              :     }
     253              : 
     254              : private:
     255              :     /** \brief Whether the buffer is considered read-only or not.
     256              :      *
     257              :      * When creating the streambuf with a constant memory buffer, this
     258              :      * parameter is set to true. This prevents writes to the file. In
     259              :      * other words, the memory will never be updated.
     260              :      */
     261              :     bool                f_read_only = false;
     262              : };
     263              : 
     264              : 
     265              : 
     266              : } // namespace snapdev
     267              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions