LCOV - code coverage report
Current view: top level - boost/buffers - any_source.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 92.2 % 90 83
Test Date: 2025-12-09 13:02:48 Functions: 100.0 % 24 24

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/beast2
       8              : //
       9              : 
      10              : #ifndef BOOST_BUFFERS_ANY_SOURCE_HPP
      11              : #define BOOST_BUFFERS_ANY_SOURCE_HPP
      12              : 
      13              : #include <boost/buffers/detail/config.hpp>
      14              : #include <boost/buffers/any_buffers.hpp>
      15              : #include <boost/buffers/buffer.hpp>
      16              : #include <boost/buffers/copy.hpp>
      17              : #include <boost/buffers/data_source.hpp>
      18              : #include <boost/buffers/error.hpp>
      19              : #include <boost/buffers/read_source.hpp>
      20              : #include <boost/buffers/slice.hpp>
      21              : #include <boost/buffers/detail/except.hpp>
      22              : #include <boost/core/span.hpp>
      23              : 
      24              : #include <type_traits>
      25              : 
      26              : namespace boost {
      27              : namespace buffers {
      28              : 
      29              : /** A type erased source.
      30              : 
      31              :     An object of this type represents shared ownership of a type-erased read\
      32              :     source or data source.
      33              :     It provides a uniform interface for reading the source data regardless of
      34              :     how the source is implemented. Accessing the bytes is achieved by calling
      35              :     @ref read which reads data into a caller-provided buffer. Alternatively,
      36              :     when @ref has_buffers returns `true` the source consists of buffers in memory,
      37              :     and they can be accessed directly by calling @ref get_buffers.
      38              : 
      39              :     Example sources include:
      40              :     - in-memory buffers
      41              :     - streaming file data
      42              :     - generated data
      43              : 
      44              :     @note @ref any_source is copyable, and the copies share ownership of the
      45              :     underlying source. Changes to the state of one copy, such as reading
      46              :     or rewinding, will be visible in all copies.
      47              : 
      48              :     Type-erased sources can always be rewound to the beginning by
      49              :     calling @ref rewind. Therefore, a source can be read multiple times.
      50              : 
      51              :     @par Thread Safety
      52              :     Unsafe.
      53              : */
      54              : class any_source
      55              : {
      56              : public:
      57              :     /** Constructor
      58              : 
      59              :         Default-constructed sources are empty.
      60              :     */
      61              :     BOOST_BUFFERS_DECL
      62              :     any_source() noexcept;
      63              : 
      64              :     /** Constructor
      65              : 
      66              :         After the move, the moved-from source will be empty.
      67              :     */
      68              :     BOOST_BUFFERS_DECL
      69              :     any_source(any_source&&) noexcept;
      70              : 
      71              :     /** Constructor
      72              : 
      73              :         After the copy, both sources share ownership of the same underlying source.
      74              :     */
      75              :     any_source(any_source const&) = default;
      76              : 
      77              :     /** Assignment
      78              : 
      79              :         After the move, the moved-from source will be empty.
      80              :     */
      81              :     BOOST_BUFFERS_DECL
      82              :     any_source& operator=(any_source&&) noexcept;
      83              : 
      84              :     /** Assignment
      85              : 
      86              :         After the copy, both sources share ownership of the same underlying source.
      87              :     */
      88              :     any_source& operator=(any_source const&) = default;
      89              : 
      90              :     /** Construct a data source.
      91              :     */
      92              :     template<class DataSource, typename std::enable_if<
      93              :         std::conditional<
      94              :             std::is_same<typename std::decay<
      95              :                 DataSource>::type, any_source>::value,
      96              :             std::false_type,
      97              :             is_data_source<typename std::decay<DataSource>::type>
      98              :         >::type::value, int>::type = 0>
      99              :     any_source(DataSource&& source);
     100              : 
     101              :     /** Construct a read source.
     102              :     */
     103              :     template<class ReadSource, typename std::enable_if<
     104              :         std::conditional<
     105              :             std::is_same<typename std::decay<
     106              :                 ReadSource>::type, any_source>::value,
     107              :             std::false_type,
     108              :             is_read_source<typename std::decay<ReadSource>::type>
     109              :         >::type::value, int>::type = 0>
     110              :     any_source(ReadSource&& source);
     111              : 
     112              :     /** Construct a read source with a known size.
     113              :     */
     114              :     template<class ReadSource, typename std::enable_if<
     115              :         std::conditional<
     116              :             std::is_same<typename std::decay<
     117              :                 ReadSource>::type, any_source>::value,
     118              :             std::false_type,
     119              :             is_read_source<typename std::decay<ReadSource>::type>
     120              :         >::type::value, int>::type = 0>
     121              :     any_source(
     122              :         std::size_t known_size,
     123              :         ReadSource&& source);
     124              : 
     125              :     /** Return `true` if the size of the source is known.
     126              :     */
     127           11 :     bool has_size() const noexcept
     128              :     {
     129           11 :         return sp_->has_size();
     130              :     }
     131              : 
     132              :     /** Return `true` if the source consists of buffers in memory.
     133              :         When the source consists of buffers in memory, they can
     134              :         also be accessed directly using @ref get_buffers.
     135              :     */
     136           11 :     bool has_buffers() const noexcept
     137              :     {
     138           11 :         return sp_->has_buffers();
     139              :     }
     140              : 
     141              :     /** Return the size of the source, if available.
     142              :         @throw std::invalid_argument if @ref has_size returns `false`.
     143              :         @return The size of the source in bytes.
     144              :     */
     145           11 :     auto size() const -> std::size_t
     146              :     {
     147           11 :         return sp_->size();
     148              :     }
     149              : 
     150              :     /** Return the buffers representing the source, if available.
     151              :         @throw std::invalid_argument if @ref has_buffers returns `false`.
     152              :         @return A buffer sequence representing the source.
     153              :     */
     154           11 :     auto data() const ->
     155              :         any_const_buffers
     156              :     {
     157           11 :         return sp_->data();
     158              :     }
     159              : 
     160              :     /** Rewind the source to the beginning.
     161              :         This allows the source to be accessed from the start when calling @read.
     162              :     */
     163          158 :     void rewind()
     164              :     {
     165          158 :         sp_->rewind();
     166          158 :     }
     167              : 
     168              :     /** Read from the source into a caller-provided buffer.
     169              : 
     170              :         When the last byte of data has been read,
     171              :         @p ec is set to @ref error::eof.
     172              : 
     173              :         @param dest The buffer sequence to write to
     174              :         @param ec Set to the error, if any occurred.
     175              :         @return The number of bytes read, which may be
     176              :         less than `size(dest)`.
     177              :     */
     178              :     template<class MutableBufferSequence>
     179          147 :     auto read(
     180              :         MutableBufferSequence const& dest,
     181              :         system::error_code& ec) ->
     182              :             std::size_t
     183              :     {
     184          147 :         std::size_t result = 0;
     185          147 :         constexpr std::size_t N = 16;
     186          147 :         std::size_t n = 0;
     187          147 :         mutable_buffer mb[N];
     188          147 :         auto it = buffers::begin(dest);
     189          147 :         auto const end_ = buffers::end(dest);
     190          147 :         if(it == end_)
     191            0 :             return 0;
     192            0 :         for(;;)
     193              :         {
     194          147 :             mb[n++] = *it++;
     195          147 :             if( n < N &&
     196              :                 it != end_)
     197            0 :                 continue;
     198          147 :             span<mutable_buffer const> dest1{ mb, n };
     199          147 :             auto const nread = sp_->read(dest1, ec);
     200          147 :             BOOST_ASSERT(
     201              :                 ec.failed() ||
     202              :                 nread == buffers::size(dest1));
     203          147 :             result += nread;
     204          147 :             if(ec.failed())
     205          147 :                 break;
     206            0 :             if(it == end_)
     207            0 :                 break;
     208            0 :             n = 0;
     209              :         }
     210          147 :         return result;
     211              :     }
     212              : 
     213              : private:
     214              :     struct BOOST_BUFFERS_DECL
     215              :         any_impl
     216              :     {
     217              :         virtual ~any_impl() = 0;
     218              :         virtual bool has_size() const noexcept;
     219              :         virtual bool has_buffers() const noexcept;
     220              :         virtual std::size_t size() const;
     221              :         virtual auto data() const -> any_const_buffers;
     222              :         virtual void rewind() = 0;
     223              :         virtual std::size_t read(
     224              :             span<mutable_buffer const> dest,
     225              :             system::error_code& ec) = 0;
     226              :     };
     227              : 
     228              :     template<class> struct data_model;
     229              :     template<class> struct read_model;
     230              :     template<class> struct sized_read_model;
     231              : 
     232              :     std::shared_ptr<any_impl> sp_;
     233              : };
     234              : 
     235              : //-----------------------------------------------
     236              : 
     237              : template<class DataSource>
     238              : struct any_source::
     239              :     data_model
     240              :     : any_source::any_impl
     241              : {
     242              :     typename std::decay<DataSource>::type source_;
     243              :     std::size_t size_ = 0;
     244              :     std::size_t nread_ = 0;
     245              : 
     246              :     template<class DataSource_>
     247            2 :     explicit data_model(
     248              :         DataSource_&& source) noexcept
     249            4 :         : source_(std::forward<DataSource_>(source))
     250            2 :         , size_(buffers::size(source_.data()))
     251              :     {
     252            2 :     }
     253              : 
     254            3 :     bool has_size() const noexcept override
     255              :     {
     256            3 :         return true;
     257              :     }
     258              : 
     259            3 :     bool has_buffers() const noexcept override
     260              :     {
     261            3 :         return true;
     262              :     }
     263              : 
     264            3 :     std::size_t size() const override
     265              :     {
     266            3 :         return size_;
     267              :     }
     268              : 
     269              :     any_const_buffers
     270            3 :     data() const override
     271              :     {
     272            3 :         return source_.data();
     273              :     }
     274              : 
     275           51 :     void rewind() override
     276              :     {
     277           51 :         nread_ = 0;
     278           51 :     }
     279              : 
     280           48 :     std::size_t read(
     281              :         span<mutable_buffer const> dest,
     282              :         system::error_code& ec) override
     283              :     {
     284           48 :         std::size_t n = copy(dest,
     285           48 :             sans_prefix(source_.data(), nread_));
     286           48 :         nread_ += n;
     287           48 :         if(nread_ >= size_)
     288           48 :             ec = error::eof;
     289              :         else
     290            0 :             ec = {};
     291           48 :         return n;
     292              :     }
     293              : };
     294              : 
     295              : //-----------------------------------------------
     296              : 
     297              : template<class ReadSource>
     298              : struct any_source::
     299              :     read_model : any_source::any_impl
     300              : {
     301              :     ReadSource source_;
     302              : 
     303              :     template<class ReadSource_>
     304            3 :     explicit read_model(
     305              :         ReadSource_&& source)
     306            3 :         : source_(std::forward<ReadSource_>(source))
     307              :     {
     308            3 :     }
     309              : 
     310           68 :     void rewind() override
     311              :     {
     312           68 :         source_.rewind();
     313           68 :     }
     314              : 
     315           64 :     std::size_t read(
     316              :         span<mutable_buffer const> dest,
     317              :         system::error_code& ec) override
     318              :     {
     319           64 :         return source_.read(dest, ec);
     320              :     }
     321              : };
     322              : 
     323              : //-----------------------------------------------
     324              : 
     325              : template<class ReadSource>
     326              : struct any_source::
     327              :     sized_read_model : any_source::any_impl
     328              : {
     329              :     std::size_t size_;
     330              :     ReadSource source_;
     331              : 
     332              :     template<class ReadSource_>
     333            1 :     explicit sized_read_model(
     334              :         ReadSource_&& source,
     335              :         std::size_t known_size)
     336            1 :         : size_(known_size)
     337            1 :         , source_(std::forward<ReadSource_>(source))
     338              :     {
     339            1 :     }
     340              : 
     341            1 :     bool has_size() const noexcept override
     342              :     {
     343            1 :         return true;
     344              :     }
     345              : 
     346            1 :     std::size_t size() const override
     347              :     {
     348            1 :         return size_;
     349              :     }
     350              : 
     351           17 :     void rewind() override
     352              :     {
     353           17 :         source_.rewind();
     354           17 :     }
     355              : 
     356              :     std::size_t
     357           16 :     read(
     358              :         span<mutable_buffer const> dest,
     359              :         system::error_code& ec) override
     360              :     {
     361           16 :         return source_.read(dest, ec);
     362              :     }
     363              : };
     364              : 
     365              : //-----------------------------------------------
     366              : 
     367              : template<class DataSource, typename std::enable_if<
     368              :     std::conditional<
     369              :         std::is_same<typename std::decay<
     370              :             DataSource>::type, any_source>::value,
     371              :         std::false_type,
     372              :         is_data_source<typename std::decay<DataSource>::type>
     373              :     >::type::value, int>::type>
     374            2 : any_source::
     375              : any_source(
     376            2 :     DataSource&& source)
     377              : {
     378              :     // VFALCO this requires DataSource to be nothrow
     379              :     // move constructible for strong exception safety.
     380              :     using type = typename std::decay<DataSource>::type;
     381            2 :     sp_ = std::make_shared<data_model<type>>(
     382              :         std::forward<DataSource>(source));
     383            2 : }
     384              : 
     385              : template<class ReadSource, typename std::enable_if<
     386              :     std::conditional<
     387              :         std::is_same<typename std::decay<
     388              :             ReadSource>::type, any_source>::value,
     389              :         std::false_type,
     390              :         is_read_source<typename std::decay<ReadSource>::type>
     391              :     >::type::value, int>::type>
     392            3 : any_source::
     393              : any_source(
     394            3 :     ReadSource&& source)
     395              : {
     396              :     using type = typename std::decay<ReadSource>::type;
     397            3 :     sp_ = std::make_shared<read_model<type>>(
     398              :         std::forward<ReadSource>(source));
     399            3 : }
     400              : 
     401              : /** Construct a streaming source source with a known size.
     402              : */
     403              : template<class ReadSource, typename std::enable_if<
     404              :     std::conditional<
     405              :         std::is_same<typename std::decay<
     406              :             ReadSource>::type, any_source>::value,
     407              :         std::false_type,
     408              :         is_read_source<typename std::decay<ReadSource>::type>
     409              :     >::type::value, int>::type>
     410            1 : any_source::
     411              : any_source(
     412              :     std::size_t known_size,
     413            1 :     ReadSource&& source)
     414              : {
     415              :     using type = typename std::decay<ReadSource>::type;
     416            1 :     sp_ = std::make_shared<sized_read_model<type>>(
     417              :         std::forward<ReadSource>(source), known_size);
     418            1 : }
     419              : 
     420              : } // buffers
     421              : } // boost
     422              : 
     423              : #endif
        

Generated by: LCOV version 2.1