LCOV - code coverage report
Current view: top level - boost/buffers - any_buffers.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 93.2 % 146 136
Test Date: 2025-12-09 13:02:48 Functions: 81.8 % 154 126

            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/buffers
       8              : //
       9              : 
      10              : #ifndef BOOST_BUFFERS_ANY_BUFFERS_HPP
      11              : #define BOOST_BUFFERS_ANY_BUFFERS_HPP
      12              : 
      13              : #include <boost/buffers/detail/config.hpp>
      14              : #include <boost/buffers/buffer.hpp>
      15              : #include <boost/core/null_deleter.hpp>
      16              : #include <boost/core/detail/static_assert.hpp>
      17              : #include <boost/assert.hpp>
      18              : #include <cstddef>
      19              : #include <memory>
      20              : #include <new>
      21              : #include <type_traits>
      22              : 
      23              : namespace boost {
      24              : namespace buffers {
      25              : 
      26              : /** A type-erased buffer sequence.
      27              : 
      28              :     This class template wraps any buffer sequence and
      29              :     exposes it through a uniform interface, hiding the
      30              :     concrete type. Iteration is performed via a type-erased
      31              :     bidirectional iterator.
      32              : 
      33              :     The implementation uses small buffer optimization (SBO)
      34              :     for iterators that are small, trivially aligned, and
      35              :     nothrow copy constructible. Larger iterators fall back
      36              :     to an index-based traversal strategy.
      37              : 
      38              :     @tparam IsConst If `true`, the sequence yields
      39              :     @ref const_buffer elements. If `false`, it yields
      40              :     @ref mutable_buffer elements.
      41              : 
      42              :     @see any_const_buffers, any_mutable_buffers
      43              : */
      44              : template<bool IsConst>
      45              : class any_buffers
      46              : {
      47              : public:
      48              :     /** The buffer type returned when dereferencing iterators.
      49              : 
      50              :         This is @ref const_buffer when `IsConst` is `true`,
      51              :         otherwise @ref mutable_buffer.
      52              :     */
      53              :     using value_type = typename std::conditional<
      54              :         IsConst, const_buffer, mutable_buffer>::type;
      55              : 
      56              :     /** A bidirectional iterator over the buffer sequence.
      57              : 
      58              :         @see begin, end
      59              :     */
      60              :     class const_iterator;
      61              : 
      62              :     /** Destructor.
      63              :     */
      64          460 :     ~any_buffers() = default;
      65              : 
      66              :     /** Constructor.
      67              :         Default-constructed objects are empty with zero length.
      68              :     */
      69              :     BOOST_BUFFERS_DECL
      70              :     any_buffers() noexcept;
      71              : 
      72              :     /** Constructor.
      73              :     */
      74          439 :     any_buffers(
      75              :         any_buffers const& other) noexcept
      76          439 :     {
      77          439 :         other.sp_->copy(*this, other.sp_);
      78          439 :     }
      79              : 
      80              :     /** Assignment.
      81              :     */
      82              :     any_buffers&
      83            0 :     operator=(
      84              :         any_buffers const& other) noexcept
      85              :     {
      86            0 :         if(this == &other)
      87            0 :             return *this;
      88            0 :         other.sp_->copy(*this, other.sp_);
      89            0 :         return *this;
      90              :     }
      91              : 
      92              :     /** Constructor.
      93              : 
      94              :         The type-erased buffer sequence is constructed
      95              :         from the specified buffer sequence, which must satisfy
      96              :         `ConstBufferSequence`. If `IsConst` is `false`, must
      97              :         also satisfy `MutableBufferSequence`.
      98              : 
      99              :         @param buffers The buffer sequence to type-erase.
     100              :     */
     101              :     template<class BufferSequence
     102              :         , class = typename std::enable_if<! std::is_same<
     103              :             any_buffers, typename std::decay<BufferSequence
     104              :                 >::type>::value>::type>
     105           14 :     any_buffers(
     106              :         BufferSequence&& buffers)
     107           14 :     {
     108              :         BOOST_CORE_STATIC_ASSERT(
     109              :             is_const_buffer_sequence<BufferSequence>::value && (IsConst ||
     110              :             is_mutable_buffer_sequence<BufferSequence>::value));
     111              :         using T = typename std::decay<BufferSequence>::type;
     112           14 :         construct(std::forward<BufferSequence>(buffers),
     113              :             std::integral_constant<bool, (
     114              :                 sizeof(impl<T>) <= sbo_size)>{});
     115           14 :     }
     116              : 
     117              :     /** Return an iterator to the beginning.
     118              : 
     119              :         @return An iterator pointing to the first buffer,
     120              :         or `end()` if the sequence is empty.
     121              :     */
     122              :     const_iterator begin() const noexcept;
     123              : 
     124              :     /** Return an iterator to the end.
     125              : 
     126              :         @return An iterator pointing one past the last buffer.
     127              :     */
     128              :     const_iterator end() const noexcept;
     129              : 
     130              : private:
     131              :     friend struct any_buffers_test;
     132              : 
     133              :     static constexpr std::size_t sbo_size = 6 * sizeof(void*);
     134              : 
     135              :     static constexpr std::size_t iter_sbo_size = 4 * sizeof(void*);
     136              : 
     137              :     struct BOOST_SYMBOL_VISIBLE
     138              :         any_impl
     139              :     {
     140           23 :         virtual ~any_impl() = default;
     141              :         virtual bool is_small_buffers() const noexcept = 0;
     142              :         virtual bool is_small_iter() const noexcept = 0;
     143              :         virtual void copy(any_buffers& dest,
     144              :             std::shared_ptr<any_impl const> const&) const = 0;
     145              :         virtual void it_copy(void*, void const*) const = 0;
     146              :         virtual void it_destroy(void*) const = 0;
     147              :         virtual void inc(void*) const = 0;
     148              :         virtual void dec(void*) const = 0;
     149              :         virtual auto deref(void const*) const -> value_type = 0;
     150              :         virtual bool equal(void const*, void const*) const = 0;
     151              :         virtual void begin(void*) const = 0;
     152              :         virtual void end(void*) const = 0;
     153              :     };
     154              : 
     155              :     template<class T, bool IsIterSmall = (sizeof(decltype(
     156              :         buffers::begin(std::declval<T const>()))) <= iter_sbo_size)>
     157              :     struct impl;
     158              : 
     159              :     // small buffer sequence
     160              :     template<class T>
     161           12 :     void construct(T&& t, std::true_type)
     162              :     {
     163              :         using U = typename std::decay<T>::type;
     164           12 :         sp_ = {
     165           12 :             ::new(&storage_) impl<U>(std::forward<T>(t)),
     166              :             null_deleter{} };
     167           12 :     }
     168              : 
     169              :     template<class T>
     170            2 :     void construct(T&& t, std::false_type)
     171              :     {
     172              :         using U = typename std::decay<T>::type;
     173            2 :         sp_ = std::make_shared<impl<U>>(std::forward<T>(t));
     174            2 :     }
     175              : 
     176            7 :     bool is_small_buffers() const noexcept
     177              :     {
     178            7 :         return sp_->is_small_buffers();
     179              :     }
     180              : 
     181            7 :     bool is_small_iter() const noexcept
     182              :     {
     183            7 :         return sp_->is_small_iter();
     184              :     }
     185              : 
     186              :     alignas(std::max_align_t)
     187              :         unsigned char mutable storage_[sbo_size] = {};
     188              :     std::shared_ptr<any_impl const> sp_;
     189              : };
     190              : 
     191              : //-----------------------------------------------
     192              : 
     193              : /** Alias for a type-erased const buffer sequence.
     194              : 
     195              :     Equivalent to `any_buffers<true>`.
     196              : 
     197              :     @see any_buffers, any_mutable_buffers
     198              : */
     199              : using any_const_buffers = any_buffers<true>;
     200              : 
     201              : /** Alias for a type-erased mutable buffer sequence.
     202              : 
     203              :     Equivalent to `any_buffers<false>`.
     204              : 
     205              :     @see any_buffers, any_const_buffers
     206              : */
     207              : using any_mutable_buffers = any_buffers<false>;
     208              : 
     209              : //-----------------------------------------------
     210              : 
     211              : // small iterator
     212              : template<bool IsConst>
     213              : template<class T, bool>
     214              : struct any_buffers<IsConst>::
     215              :     impl : any_impl
     216              : {
     217              :     using iter_t = decltype(buffers::begin(
     218              :         std::declval<T const&>()));
     219              : 
     220              :     template<class T_>
     221          377 :     explicit impl(T_&& t) noexcept
     222          377 :         : t_(std::forward<T_>(t))
     223              :     {
     224          377 :     }
     225              : 
     226            3 :     bool is_small_buffers() const noexcept override
     227              :     {
     228            3 :         return sizeof(*this) <= sbo_size;
     229              :     }
     230              : 
     231            3 :     bool is_small_iter() const noexcept override
     232              :     {
     233            3 :         return true;
     234              :     }
     235              : 
     236          365 :     void copy(any_buffers& dest, std::shared_ptr<
     237              :         any_buffers<IsConst>::any_impl const> const& sp) const override
     238              :     {
     239          365 :         copy(dest, sp, std::integral_constant<bool,
     240              :             sizeof(*this) <= sbo_size>{});
     241          365 :     }
     242              : 
     243          365 :     void copy(
     244              :         any_buffers& dest, std::shared_ptr<
     245              :             any_buffers<IsConst>::any_impl const> const&,
     246              :         std::true_type) const // small buffers
     247              :     {
     248          365 :         dest.sp_ = std::shared_ptr<impl<T>>(
     249          365 :             ::new(&dest.storage_) impl<T>(t_),
     250              :             null_deleter{} );
     251          365 :     }
     252              : 
     253              :     void copy(
     254              :         any_buffers& dest, std::shared_ptr<
     255              :             any_buffers<IsConst>::any_impl const> const&,
     256              :         std::false_type) const
     257              :     {
     258              :         dest.sp_ = std::make_shared<impl<T>>(t_);
     259              :     }
     260              : 
     261         5592 :     void it_copy(void* dest, void const* src) const override
     262              :     {
     263         5592 :         ::new(dest) iter_t(*static_cast<iter_t const*>(src));
     264         5592 :     }
     265              : 
     266        10422 :     void it_destroy(void* p) const override
     267              :     {
     268        10422 :         static_cast<iter_t*>(p)->~iter_t();
     269        10422 :     }
     270              : 
     271         3779 :     void inc(void* p) const override
     272              :     {
     273         3779 :         ++(*static_cast<iter_t*>(p));
     274         3779 :     }
     275              : 
     276          732 :     void dec(void* p) const  override
     277              :     {
     278          732 :         --(*static_cast<iter_t*>(p));
     279          732 :     }
     280              : 
     281         2254 :     value_type deref(void const* p) const override
     282              :     {
     283         2254 :         return *(*static_cast<iter_t const*>(p));
     284              :     }
     285              : 
     286         4840 :     bool equal(void const* it0, void const* it1) const override
     287              :     {
     288         4840 :         return  *static_cast<iter_t const*>(it0) ==
     289         4840 :                 *static_cast<iter_t const*>(it1);
     290              :     }
     291              : 
     292         4599 :     void begin(void* p) const override
     293              :     {
     294         4599 :         ::new(p) iter_t(buffers::begin(t_));
     295         4599 :     }
     296              : 
     297          231 :     void end(void* p) const override
     298              :     {
     299          231 :         ::new(p) iter_t(buffers::end(t_));
     300          231 :     }
     301              : 
     302              : private:
     303              :     T t_;
     304              : };
     305              : 
     306              : template<bool IsConst>
     307              : template<class T>
     308              : struct any_buffers<IsConst>::
     309              :     impl<T, false> : any_impl
     310              : {
     311              :     struct iter_t
     312              :     {
     313              :         std::size_t i;
     314              :     };
     315              : 
     316              :     template<class T_>
     317           20 :     explicit impl(T_&& t) noexcept
     318           21 :         : t_(std::forward<T_>(t))
     319           39 :         , len_(length(t_))
     320              :     {
     321           20 :     }
     322              : 
     323            1 :     bool is_small_buffers() const noexcept override
     324              :     {
     325            1 :         return sizeof(*this) <= any_buffers<IsConst>::sbo_size;
     326              :     }
     327              : 
     328            1 :     bool is_small_iter() const noexcept override
     329              :     {
     330            1 :         return false;
     331              :     }
     332              : 
     333           18 :     void copy(
     334              :         any_buffers<IsConst>& dest, std::shared_ptr<
     335              :             any_buffers<IsConst>::any_impl const> const& sp) const override
     336              :     {
     337           18 :         copy(dest, sp, std::integral_constant<bool,
     338              :             sizeof(*this) <= any_buffers<IsConst>::sbo_size>{});
     339           18 :     }
     340              : 
     341              :     void copy(
     342              :         any_buffers<IsConst>& dest, std::shared_ptr<
     343              :             any_buffers<IsConst>::any_impl const> const&,
     344              :         std::true_type) const // small buffers
     345              :     {
     346              :         dest.sp_ = std::shared_ptr<impl<T>>(
     347              :             ::new(&dest.storage_) impl<T>(t_),
     348              :             null_deleter{});
     349              :     }
     350              : 
     351           18 :     void copy(
     352              :         any_buffers<IsConst>& dest, std::shared_ptr<
     353              :             any_buffers<IsConst>::any_impl const> const&,
     354              :         std::false_type) const
     355              :     {
     356           18 :         dest.sp_ = std::make_shared<impl<T>>(t_);
     357           18 :     }
     358              : 
     359          216 :     void it_copy(void* dest, void const* src) const override
     360              :     {
     361          216 :         ::new(dest) iter_t(*static_cast<iter_t const*>(src));
     362          216 :     }
     363              : 
     364          450 :     void it_destroy(void* p) const override
     365              :     {
     366          450 :         static_cast<iter_t*>(p)->~iter_t();
     367          450 :     }
     368              : 
     369            2 :     void inc(void* p) const override
     370              :     {
     371            2 :         ++static_cast<iter_t*>(p)->i;
     372            2 :     }
     373              : 
     374            0 :     void dec(void* p) const  override
     375              :     {
     376            0 :         --static_cast<iter_t*>(p)->i;
     377            0 :     }
     378              : 
     379              :     typename any_buffers<IsConst>::value_type
     380            2 :     deref(void const* p) const override
     381              :     {
     382            2 :         auto const& it_ = *static_cast<iter_t const*>(p);
     383            2 :         auto it = buffers::begin(t_);
     384            3 :         for(auto i = it_.i; i; --i)
     385            1 :             ++it;
     386            2 :         return *it;
     387            0 :     }
     388              : 
     389          126 :     bool equal(void const* it0, void const* it1) const override
     390              :     {
     391          126 :         return  static_cast<iter_t const*>(it0)->i ==
     392          126 :                 static_cast<iter_t const*>(it1)->i;
     393              :     }
     394              : 
     395          210 :     void begin(void* p) const override
     396              :     {
     397          210 :         ::new(p) iter_t{ 0 };
     398          210 :     }
     399              : 
     400           24 :     void end(void* p) const override
     401              :     {
     402           24 :         ::new(p) iter_t{ len_ };
     403           24 :     }
     404              : 
     405              : private:
     406              :     T t_;
     407              :     std::size_t len_;
     408              : };
     409              : 
     410              : //-----------------------------------------------
     411              : 
     412              : /** A bidirectional iterator for @ref any_buffers.
     413              : 
     414              :     This iterator provides type-erased access to the
     415              :     underlying buffer sequence elements. It models
     416              :     `BidirectionalIterator` and returns buffer objects
     417              :     by value.
     418              : */
     419              : template<bool IsConst>
     420              : class any_buffers<IsConst>::
     421              :     const_iterator
     422              : {
     423              : public:
     424              :     /** The buffer type returned by dereferencing.
     425              :     */
     426              :     using value_type = typename
     427              :         any_buffers<IsConst>::value_type;
     428              : 
     429              :     /** The type returned by `operator*`.
     430              : 
     431              :         Buffers are returned by value.
     432              :     */
     433              :     using reference = value_type;
     434              : 
     435              :     /** Pointer type (void, not used).
     436              :     */
     437              :     using pointer = void;
     438              : 
     439              :     /** Signed integer type for iterator differences.
     440              :     */
     441              :     using difference_type = std::ptrdiff_t;
     442              : 
     443              :     /** Iterator category tag.
     444              :     */
     445              :     using iterator_category =
     446              :         std::bidirectional_iterator_tag;
     447              : 
     448              : #if defined(__cpp_concepts) || defined(__cpp_lib_concepts)
     449              :     /** Iterator concept tag (C++20).
     450              :     */
     451              :     using iterator_concept = std::bidirectional_iterator_tag;
     452              : #endif
     453              : 
     454              :     /** Destructor.
     455              : 
     456              :         Destroys the type-erased iterator state.
     457              :     */
     458        11838 :     ~const_iterator()
     459              :     {
     460        11838 :         sp_->it_destroy(&storage_);
     461        11838 :     }
     462              : 
     463              :     /** Default constructor.
     464              : 
     465              :         Constructs a singular iterator. A default-constructed
     466              :         iterator may only be assigned to or destroyed.
     467              :     */
     468              :     const_iterator() noexcept;
     469              : 
     470              :     /** Copy constructor.
     471              : 
     472              :         @param other The iterator to copy.
     473              :     */
     474         6242 :     const_iterator(
     475              :         const_iterator const& other) noexcept
     476         6242 :         : sp_(other.sp_)
     477              :     {
     478         6242 :         sp_->it_copy(&storage_, &other.storage_);
     479         6242 :     }
     480              : 
     481              :     /** Copy assignment.
     482              : 
     483              :         @param other The iterator to copy.
     484              :         @return `*this`
     485              :     */
     486              :     const_iterator& operator=(
     487              :         const_iterator const& other) noexcept
     488              :     {
     489              :         if(this == &other)
     490              :             return *this;
     491              :         sp_->it_destroy(&storage_);
     492              :         sp_ = other.sp_;
     493              :         sp_->it_copy(&storage_, &other.storage_);
     494              :         return *this;
     495              :     }
     496              : 
     497              :     /** Test for equality.
     498              : 
     499              :         @param other The iterator to compare.
     500              :         @return `true` if both iterators point to the
     501              :         same element of the same sequence.
     502              :     */
     503              :     bool
     504         5247 :     operator==(
     505              :         const_iterator const& other) const noexcept
     506              :     {
     507         5247 :         if(sp_ != other.sp_)
     508            0 :             return false;
     509         5247 :         return sp_->equal(&storage_, &other.storage_);
     510              :     }
     511              : 
     512              :     /** Test for inequality.
     513              : 
     514              :         @param other The iterator to compare.
     515              :         @return `true` if the iterators point to
     516              :         different elements or different sequences.
     517              :     */
     518              :     bool
     519         1025 :     operator!=(
     520              :         const_iterator const& other) const noexcept
     521              :     {
     522         1025 :         return !(*this == other);
     523              :     }
     524              : 
     525              :     /** Dereference the iterator.
     526              : 
     527              :         @return The buffer at the current position.
     528              : 
     529              :         @pre The iterator is dereferenceable
     530              :         (not default-constructed or past-the-end).
     531              :     */
     532              :     reference
     533         2262 :     operator*() const noexcept
     534              :     {
     535         2262 :         return sp_->deref(&storage_);
     536              :     }
     537              : 
     538              :     /** Pre-increment.
     539              : 
     540              :         Advances the iterator to the next buffer.
     541              : 
     542              :         @return `*this`
     543              : 
     544              :         @pre The iterator is incrementable.
     545              :     */
     546              :     const_iterator&
     547         3783 :     operator++() noexcept
     548              :     {
     549         3783 :         sp_->inc(&storage_);
     550         3783 :         return *this;
     551              :     }
     552              : 
     553              :     /** Post-increment.
     554              : 
     555              :         Advances the iterator to the next buffer.
     556              : 
     557              :         @return A copy of the iterator before incrementing.
     558              : 
     559              :         @pre The iterator is incrementable.
     560              :     */
     561              :     const_iterator
     562            6 :     operator++(int) noexcept
     563              :     {
     564            6 :         auto temp = *this;
     565            6 :         ++(*this);
     566            6 :         return temp;
     567              :     }
     568              : 
     569              :     /** Pre-decrement.
     570              : 
     571              :         Moves the iterator to the previous buffer.
     572              : 
     573              :         @return `*this`
     574              : 
     575              :         @pre The iterator is decrementable.
     576              :     */
     577              :     const_iterator&
     578          734 :     operator--() noexcept
     579              :     {
     580          734 :         sp_->dec(&storage_);
     581          734 :         return *this;
     582              :     }
     583              : 
     584              :     /** Post-decrement.
     585              : 
     586              :         Moves the iterator to the previous buffer.
     587              : 
     588              :         @return A copy of the iterator before decrementing.
     589              : 
     590              :         @pre The iterator is decrementable.
     591              :     */
     592              :     const_iterator
     593           78 :     operator--(int) noexcept
     594              :     {
     595           78 :         auto temp = *this;
     596           78 :         --(*this);
     597           78 :         return temp;
     598              :     }
     599              : 
     600              : private:
     601              :     friend class any_buffers;
     602              : 
     603              :     struct begin_tag {};
     604              :     struct end_tag {};
     605              : 
     606         5262 :     const_iterator(begin_tag, std::shared_ptr<
     607              :         any_impl const> const& sp) noexcept
     608         5262 :         : sp_(sp)
     609              :     {
     610         5262 :         sp_->begin(&storage_);
     611         5262 :     }
     612              : 
     613          334 :     const_iterator(end_tag, std::shared_ptr<
     614              :         any_impl const> const& sp) noexcept
     615          334 :         : sp_(sp)
     616              :     {
     617          334 :         sp_->end(&storage_);
     618          334 :     }
     619              : 
     620              :     alignas(std::max_align_t)
     621              :         unsigned char mutable storage_[iter_sbo_size] = {};
     622              :     std::shared_ptr<any_buffers<IsConst>::any_impl const> sp_;
     623              : };
     624              : 
     625              : //-----------------------------------------------
     626              : 
     627              : template<>
     628              : BOOST_BUFFERS_DECL
     629              : any_buffers<true>::
     630              : any_buffers() noexcept;
     631              : 
     632              : template<>
     633              : BOOST_BUFFERS_DECL
     634              : any_buffers<false>::
     635              : any_buffers() noexcept;
     636              : 
     637              : template<>
     638              : BOOST_BUFFERS_DECL
     639              : any_buffers<true>::
     640              : const_iterator::
     641              : const_iterator() noexcept;
     642              : 
     643              : template<>
     644              : BOOST_BUFFERS_DECL
     645              : any_buffers<false>::
     646              : const_iterator::
     647              : const_iterator() noexcept;
     648              : 
     649              : //-----------------------------------------------
     650              : 
     651              : template<bool IsConst>
     652              : auto
     653         5262 : any_buffers<IsConst>::
     654              : begin() const noexcept ->
     655              :     const_iterator
     656              : {
     657              :     return const_iterator(typename
     658         5262 :         const_iterator::begin_tag{}, sp_);
     659              : }
     660              : 
     661              : template<bool IsConst>
     662              : auto
     663          334 : any_buffers<IsConst>::
     664              : end() const noexcept ->
     665              :     const_iterator
     666              : {
     667              :     return const_iterator(typename
     668          334 :         const_iterator::end_tag{}, sp_);
     669              : }
     670              : 
     671              : } // buffers
     672              : } // boost
     673              : 
     674              : #endif
        

Generated by: LCOV version 2.1