LCOV - code coverage report
Current view: top level - capy/buffers - string_dynamic_buffer.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 53 53
Test Date: 2026-03-09 21:20:58 Functions: 100.0 % 10 10

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.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/capy
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP
      11                 : #define BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP
      12                 : 
      13                 : #include <boost/capy/detail/config.hpp>
      14                 : #include <boost/capy/buffers.hpp>
      15                 : #include <boost/capy/detail/except.hpp>
      16                 : #include <string>
      17                 : 
      18                 : namespace boost {
      19                 : namespace capy {
      20                 : 
      21                 : /** A dynamic buffer backed by a `std::basic_string`.
      22                 : 
      23                 :     This adapter wraps an externally-owned string and
      24                 :     exposes it through the @ref DynamicBuffer interface.
      25                 :     Readable bytes occupy the front of the string; writable
      26                 :     bytes are appended by `prepare` and made readable by
      27                 :     `commit`.
      28                 : 
      29                 :     @note The wrapped string must outlive this adapter.
      30                 :         Calls to `prepare`, `commit`, and `consume`
      31                 :         invalidate previously returned buffer views.
      32                 : 
      33                 :     @par Thread Safety
      34                 :     Distinct objects: Safe.
      35                 :     Shared objects: Unsafe.
      36                 : 
      37                 :     @par Example
      38                 :     @code
      39                 :     std::string s;
      40                 :     auto buf = dynamic_buffer( s, 4096 );
      41                 :     auto mb = buf.prepare( 100 );
      42                 :     // fill mb with data...
      43                 :     buf.commit( 100 );
      44                 :     // buf.data() now has 100 readable bytes
      45                 :     buf.consume( 50 );
      46                 :     @endcode
      47                 : 
      48                 :     @tparam CharT The character type.
      49                 :     @tparam Traits The character traits type.
      50                 :     @tparam Allocator The allocator type.
      51                 : 
      52                 :     @see DynamicBuffer, string_dynamic_buffer, dynamic_buffer
      53                 : */
      54                 : template<
      55                 :     class CharT,
      56                 :     class Traits = std::char_traits<CharT>,
      57                 :     class Allocator = std::allocator<CharT>>
      58                 : class basic_string_dynamic_buffer
      59                 : {
      60                 :     std::basic_string<
      61                 :         CharT, Traits, Allocator>* s_;
      62                 :     std::size_t max_size_;
      63                 : 
      64                 :     std::size_t in_size_ = 0;
      65                 :     std::size_t out_size_ = 0;
      66                 : 
      67                 : public:
      68                 :     /// Indicates this is a DynamicBuffer adapter over external storage.
      69                 :     using is_dynamic_buffer_adapter = void;
      70                 : 
      71                 :     /// The underlying string type.
      72                 :     using string_type = std::basic_string<
      73                 :         CharT, Traits, Allocator>;
      74                 : 
      75                 :     /// The ConstBufferSequence type for readable bytes.
      76                 :     using const_buffers_type = const_buffer;
      77                 : 
      78                 :     /// The MutableBufferSequence type for writable bytes.
      79                 :     using mutable_buffers_type = mutable_buffer;
      80                 : 
      81                 :     /// Destroy the buffer.
      82                 :     ~basic_string_dynamic_buffer() = default;
      83                 : 
      84                 :     /// Construct by moving from another buffer.
      85 HIT         266 :     basic_string_dynamic_buffer(
      86                 :         basic_string_dynamic_buffer&& other) noexcept
      87             266 :         : s_(other.s_)
      88             266 :         , max_size_(other.max_size_)
      89             266 :         , in_size_(other.in_size_)
      90             266 :         , out_size_(other.out_size_)
      91                 :     {
      92             266 :         other.s_ = nullptr;
      93             266 :     }
      94                 : 
      95                 :     /** Construct from an existing string.
      96                 : 
      97                 :         @param s Pointer to the string to wrap. Must
      98                 :             remain valid for the lifetime of this object.
      99                 :         @param max_size Optional upper bound on the number
     100                 :             of bytes the buffer may hold.
     101                 :     */
     102                 :     explicit
     103             427 :     basic_string_dynamic_buffer(
     104                 :         string_type* s,
     105                 :         std::size_t max_size =
     106                 :             std::size_t(-1)) noexcept
     107             427 :         : s_(s)
     108             427 :         , max_size_(
     109             427 :             max_size > s_->max_size()
     110             427 :                 ? s_->max_size()
     111             427 :                 : max_size)
     112                 :     {
     113             427 :         if(s_->size() > max_size_)
     114               1 :             s_->resize(max_size_);
     115             427 :         in_size_ = s_->size();
     116             427 :     }
     117                 : 
     118                 :     /// Copy assignment is deleted.
     119                 :     basic_string_dynamic_buffer& operator=(
     120                 :         basic_string_dynamic_buffer const&) = delete;
     121                 : 
     122                 :     /// Return the number of readable bytes.
     123                 :     std::size_t
     124            1280 :     size() const noexcept
     125                 :     {
     126            1280 :         return in_size_;
     127                 :     }
     128                 : 
     129                 :     /// Return the maximum number of bytes the buffer can hold.
     130                 :     std::size_t
     131             410 :     max_size() const noexcept
     132                 :     {
     133             410 :         return max_size_;
     134                 :     }
     135                 : 
     136                 :     /// Return the number of writable bytes without reallocation.
     137                 :     std::size_t
     138               2 :     capacity() const noexcept
     139                 :     {
     140               2 :         if(s_->capacity() <= max_size_)
     141               1 :             return s_->capacity() - in_size_;
     142               1 :         return max_size_ - in_size_;
     143                 :     }
     144                 : 
     145                 :     /// Return a buffer sequence representing the readable bytes.
     146                 :     const_buffers_type
     147             387 :     data() const noexcept
     148                 :     {
     149             387 :         return const_buffers_type(
     150             774 :             s_->data(), in_size_);
     151                 :     }
     152                 : 
     153                 :     /** Prepare writable space of at least `n` bytes.
     154                 : 
     155                 :         Invalidates iterators and references returned by
     156                 :         previous calls to `data` and `prepare`.
     157                 : 
     158                 :         @throws std::invalid_argument if `n` exceeds
     159                 :             available space.
     160                 : 
     161                 :         @param n The number of bytes to prepare.
     162                 : 
     163                 :         @return A mutable buffer of exactly `n` bytes.
     164                 :     */
     165                 :     mutable_buffers_type
     166             533 :     prepare(std::size_t n)
     167                 :     {
     168                 :         // n exceeds available space
     169             533 :         if(n > max_size_ - in_size_)
     170               1 :             detail::throw_invalid_argument();
     171                 : 
     172             532 :         if( s_->size() < in_size_ + n)
     173             531 :             s_->resize(in_size_ + n);
     174             532 :         out_size_ = n;
     175             532 :         return mutable_buffers_type(
     176            1064 :             &(*s_)[in_size_], out_size_);
     177                 :     }
     178                 : 
     179                 :     /** Move bytes from the writable to the readable area.
     180                 : 
     181                 :         Invalidates iterators and references returned by
     182                 :         previous calls to `data` and `prepare`.
     183                 : 
     184                 :         @param n The number of bytes to commit. Clamped
     185                 :             to the size of the writable area.
     186                 :     */
     187             434 :     void commit(std::size_t n) noexcept
     188                 :     {
     189             434 :         if(n < out_size_)
     190             242 :             in_size_ += n;
     191                 :         else
     192             192 :             in_size_ += out_size_;
     193             434 :         out_size_ = 0;
     194             434 :         s_->resize(in_size_);
     195             434 :     }
     196                 : 
     197                 :     /** Remove bytes from the beginning of the readable area.
     198                 : 
     199                 :         Invalidates iterators and references returned by
     200                 :         previous calls to `data` and `prepare`.
     201                 : 
     202                 :         @param n The number of bytes to consume. Clamped
     203                 :             to the number of readable bytes.
     204                 :     */
     205             168 :     void consume(std::size_t n) noexcept
     206                 :     {
     207             168 :         if(n < in_size_)
     208                 :         {
     209               3 :             s_->erase(0, n);
     210               3 :             in_size_ -= n;
     211                 :         }
     212                 :         else
     213                 :         {
     214             165 :             s_->clear();
     215             165 :             in_size_ = 0;
     216                 :         }
     217             168 :         out_size_ = 0;
     218             168 :     }
     219                 : };
     220                 : 
     221                 : /// A dynamic buffer using `std::string`.
     222                 : using string_dynamic_buffer = basic_string_dynamic_buffer<char>;
     223                 : 
     224                 : /** Create a dynamic buffer from a string.
     225                 : 
     226                 :     @param s The string to wrap.
     227                 :     @param max_size Optional maximum size limit.
     228                 :     @return A string_dynamic_buffer wrapping the string.
     229                 : */
     230                 : template<class CharT, class Traits, class Allocator>
     231                 : basic_string_dynamic_buffer<CharT, Traits, Allocator>
     232             132 : dynamic_buffer(
     233                 :     std::basic_string<CharT, Traits, Allocator>& s,
     234                 :     std::size_t max_size = std::size_t(-1))
     235                 : {
     236             132 :     return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size);
     237                 : }
     238                 : 
     239                 : } // capy
     240                 : } // boost
     241                 : 
     242                 : #endif
        

Generated by: LCOV version 2.3