LCOV - code coverage report
Current view: top level - boost/buffers - any_source.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 95.3 % 86 82
Test Date: 2025-12-08 14:54:08 Functions: 100.0 % 26 26

            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              : 
      23              : namespace boost {
      24              : namespace buffers {
      25              : 
      26              : /** A type erased source.
      27              : 
      28              :     An object of this type represents shared ownership of a type-erased read\
      29              :     source or data source.
      30              :     It provides a uniform interface for reading the source data regardless of
      31              :     how the source is implemented. Accessing the bytes is achieved by calling
      32              :     @ref read which reads data into a caller-provided buffer. Alternatively,
      33              :     when @ref has_buffers returns `true` the source consists of buffers in memory,
      34              :     and they can be accessed directly by calling @ref get_buffers.
      35              : 
      36              :     Example sources include:
      37              :     - in-memory buffers
      38              :     - streaming file data
      39              :     - generated data
      40              : 
      41              :     @note @ref any_source is copyable, and the copies share ownership of the
      42              :     underlying source. Changes to the state of one copy, such as reading
      43              :     or rewinding, will be visible in all copies.
      44              : 
      45              :     Type-erased sources can always be rewound to the beginning by
      46              :     calling @ref rewind. Therefore, a source can be read multiple times.
      47              : 
      48              :     @par Thread Safety
      49              :     Unsafe.
      50              : */
      51              : class any_source
      52              : {
      53              : public:
      54              :     /** Constructor
      55              : 
      56              :         Default-constructed sources are empty.
      57              :     */
      58              :     BOOST_BUFFERS_DECL
      59              :     any_source() noexcept;
      60              : 
      61            2 :     any_source(any_source const&) = default;
      62              : 
      63            3 :     any_source& operator=(any_source const&) = default;
      64              : 
      65              :     /** Construct a read source.
      66              :     */
      67              :     template<class ReadSource, typename std::enable_if<
      68              :         std::conditional<
      69              :             std::is_same<typename std::decay<
      70              :                 ReadSource>::type, any_source>::value,
      71              :             std::false_type,
      72              :             is_read_source<typename std::decay<ReadSource>::type>
      73              :         >::type::value, int>::type = 0>
      74              :     any_source(ReadSource&& source);
      75              : 
      76              :     /** Construct a read source with a known size.
      77              :     */
      78              :     template<class ReadSource, typename std::enable_if<
      79              :         std::conditional<
      80              :             std::is_same<typename std::decay<
      81              :                 ReadSource>::type, any_source>::value,
      82              :             std::false_type,
      83              :             is_read_source<typename std::decay<ReadSource>::type>
      84              :         >::type::value, int>::type = 0>
      85              :     any_source(
      86              :         std::size_t known_size,
      87              :         ReadSource&& source);
      88              : 
      89              :     /** Construct a data source.
      90              :     */
      91              :     template<class DataSource, typename std::enable_if<
      92              :         std::conditional<
      93              :             std::is_same<typename std::decay<
      94              :                 DataSource>::type, any_source>::value,
      95              :             std::false_type,
      96              :             is_data_source<typename std::decay<DataSource>::type>
      97              :         >::type::value, int>::type = 0>
      98              :     any_source(DataSource&& source);
      99              : 
     100              :     /** Return `true` if the size of the source is known.
     101              :     */
     102           10 :     bool has_size() const noexcept
     103              :     {
     104           10 :         return sp_->has_size();
     105              :     }
     106              : 
     107              :     /** Return `true` if the source consists of buffers in memory.
     108              :         When the source consists of buffers in memory, they can
     109              :         also be accessed directly using @ref get_buffers.
     110              :     */
     111           10 :     bool has_buffers() const noexcept
     112              :     {
     113           10 :         return sp_->has_buffers();
     114              :     }
     115              : 
     116              :     /** Return the size of the source, if available.
     117              :         @throw std::invalid_argument if @ref has_size returns `false`.
     118              :         @return The size of the source in bytes.
     119              :     */
     120           10 :     auto size() const -> std::size_t
     121              :     {
     122           10 :         return sp_->size();
     123              :     }
     124              : 
     125              :     /** Return the buffers representing the source, if available.
     126              :         @throw std::invalid_argument if @ref has_buffers returns `false`.
     127              :         @return A buffer sequence representing the source.
     128              :     */
     129           10 :     auto data() const ->
     130              :         any_const_buffers
     131              :     {
     132           10 :         return sp_->data();
     133              :     }
     134              : 
     135              :     /** Rewind the source to the beginning.
     136              :         This allows the source to be accessed from the start when calling @read.
     137              :     */
     138          154 :     void rewind()
     139              :     {
     140          154 :         sp_->rewind();
     141          154 :     }
     142              : 
     143              :     /** Read from the source into a caller-provided buffer.
     144              : 
     145              :         When the last byte of data has been read,
     146              :         @p ec is set to @ref error::eof.
     147              : 
     148              :         @param dest A pointer to the buffer to read into.
     149              :         @param n The maximum number of bytes to read.
     150              :         @param ec Set to the error, if any occurred.
     151              :         @return The number of bytes read, which may be
     152              :         less than the number requested. 
     153              :     */
     154              :     auto
     155          320 :     read(void* dest, std::size_t n,
     156              :         system::error_code& ec) ->
     157              :             std::size_t
     158              :     {
     159          320 :         return sp_->read(dest, n, ec);
     160              :     }
     161              : 
     162              : private:
     163              :     struct BOOST_BUFFERS_DECL
     164              :         any_impl
     165              :     {
     166              :         virtual ~any_impl() = 0;
     167              :         virtual bool has_size() const noexcept;
     168              :         virtual bool has_buffers() const noexcept;
     169              :         virtual std::size_t size() const;
     170              :         virtual auto data() const -> any_const_buffers;
     171              :         virtual void rewind() = 0;
     172              :         virtual std::size_t read(
     173              :             void* dest, std::size_t n,
     174              :             system::error_code& ec) = 0;
     175              :     };
     176              : 
     177              :     std::shared_ptr<any_impl> sp_;
     178              : };
     179              : 
     180              : //-----------------------------------------------
     181              : 
     182              : template<class ReadSource, typename std::enable_if<
     183              :     std::conditional<
     184              :         std::is_same<typename std::decay<
     185              :             ReadSource>::type, any_source>::value,
     186              :         std::false_type,
     187              :         is_read_source<typename std::decay<ReadSource>::type>
     188              :     >::type::value, int>::type>
     189            3 : any_source::
     190              : any_source(
     191            3 :     ReadSource&& source)
     192              : {
     193              :     struct model : any_impl
     194              :     {
     195              :         system::error_code ec_;
     196              :         typename std::decay<ReadSource>::type source_;
     197              : 
     198            3 :         explicit model(ReadSource&& source)
     199            3 :             : source_(std::forward<ReadSource>(source))
     200              :         {
     201            3 :         }
     202              : 
     203           69 :         void rewind() override
     204              :         {
     205           69 :             ec_ = {};
     206           69 :             source_.rewind();
     207           69 :         }
     208              : 
     209          154 :         std::size_t read(
     210              :             void* dest,
     211              :             std::size_t size,
     212              :             system::error_code& ec) override
     213              :         {
     214          154 :             if(ec_.failed())
     215              :             {
     216            0 :                 ec = ec_;
     217            0 :                 return 0;
     218              :             }
     219          154 :             auto nread = source_.read(
     220          154 :                 mutable_buffer(dest, size), ec);
     221          154 :             ec_ = ec;
     222          154 :             return nread;
     223              :         }
     224              :     };
     225              : 
     226            3 :     sp_ = std::make_shared<model>(
     227              :         std::forward<ReadSource>(source));
     228            3 : }
     229              : 
     230              : /** Construct a streaming source source with a known size.
     231              : */
     232              : template<class ReadSource, typename std::enable_if<
     233              :     std::conditional<
     234              :         std::is_same<typename std::decay<
     235              :             ReadSource>::type, any_source>::value,
     236              :         std::false_type,
     237              :         is_read_source<typename std::decay<ReadSource>::type>
     238              :     >::type::value, int>::type>
     239            1 : any_source::
     240              : any_source(
     241              :     std::size_t known_size,
     242            1 :     ReadSource&& source)
     243              : {
     244              :     struct model : any_impl
     245              :     {
     246              :         std::size_t size_;
     247              :         system::error_code ec_;
     248              :         typename std::decay<ReadSource>::type source_;
     249              : 
     250            1 :         model(
     251              :             ReadSource&& source,
     252              :             std::size_t known_size)
     253            1 :             : size_(known_size)
     254            1 :             , source_(std::forward<ReadSource>(source))
     255              :         {
     256            1 :         }
     257              : 
     258            1 :         bool has_size() const noexcept override
     259              :         {
     260            1 :             return true;
     261              :         }
     262              : 
     263            1 :         std::size_t size() const override
     264              :         {
     265            1 :             return size_;
     266              :         }
     267              : 
     268           17 :         void rewind() override
     269              :         {
     270           17 :             ec_ = {};
     271           17 :             source_.rewind();
     272           17 :         }
     273              : 
     274           24 :         std::size_t read(
     275              :             void* dest,
     276              :             std::size_t size,
     277              :             system::error_code& ec) override
     278              :         {
     279           24 :             if(ec_.failed())
     280              :             {
     281            0 :                 ec = ec_;
     282            0 :                 return 0;
     283              :             }
     284           24 :             auto nread = source_.read(
     285           24 :                 mutable_buffer(dest, size), ec);
     286           24 :             ec_ = ec;
     287           24 :             return nread;
     288              :         }
     289              :     };
     290              : 
     291            1 :     sp_ = std::make_shared<model>(
     292              :         std::forward<ReadSource>(source), known_size);
     293            1 : }
     294              : 
     295              : /** Construct a buffers source source.
     296              : */
     297              : template<class DataSource, typename std::enable_if<
     298              :     std::conditional<
     299              :         std::is_same<typename std::decay<
     300              :             DataSource>::type, any_source>::value,
     301              :         std::false_type,
     302              :         is_data_source<typename std::decay<DataSource>::type>
     303              :     >::type::value, int>::type>
     304            2 : any_source::
     305              : any_source(
     306            2 :     DataSource&& source)
     307              : {
     308              :     struct model : any_impl
     309              :     {
     310              :         typename std::decay<DataSource>::type source_;
     311              :         std::size_t size_ = 0;
     312              :         std::size_t nread_ = 0;
     313              : 
     314            2 :         explicit model(
     315              :             DataSource&& source) noexcept
     316            4 :             : source_(std::forward<DataSource>(source))
     317            2 :             , size_(buffers::size(source_.data()))
     318              :         {
     319            2 :         }
     320              : 
     321            3 :         bool has_size() const noexcept override
     322              :         {
     323            3 :             return true;
     324              :         }
     325              : 
     326            3 :         bool has_buffers() const noexcept override
     327              :         {
     328            3 :             return true;
     329              :         }
     330              : 
     331            3 :         std::size_t size() const override
     332              :         {
     333            3 :             return size_;
     334              :         }
     335              : 
     336              :         any_const_buffers
     337            3 :         data() const override
     338              :         {
     339            3 :             return source_.data();
     340              :         }
     341              : 
     342           51 :         void rewind() override
     343              :         {
     344           51 :             nread_ = 0;
     345           51 :         }
     346              : 
     347          126 :         std::size_t read(
     348              :             void* dest,
     349              :             std::size_t n0,
     350              :             system::error_code& ec) override
     351              :         {
     352          126 :             std::size_t n = copy(
     353          126 :                 mutable_buffer(dest, n0),
     354          126 :                 sans_prefix(source_.data(), nread_));
     355          126 :             nread_ += n;
     356          126 :             if(nread_ >= size_)
     357           48 :                 ec = error::eof;
     358              :             else
     359           78 :                 ec = {};
     360          126 :             return n;
     361              :         }
     362              :     };
     363              : 
     364              :     // VFALCO this requires DataSource to be nothrow
     365              :     // move constructible for strong exception safety.
     366            2 :     sp_ = std::make_shared<model>(
     367              :         std::forward<DataSource>(source));
     368            2 : }
     369              : 
     370              : } // buffers
     371              : } // boost
     372              : 
     373              : #endif
        

Generated by: LCOV version 2.1