LCOV - code coverage report
Current view: top level - boost/buffers - any_buffers.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 96.3 % 161 155
Test Date: 2025-12-08 17:18:02 Functions: 84.8 % 164 139

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

Generated by: LCOV version 2.1