Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:28

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_MULTI_BUFFER_HPP
0011 #define BOOST_BEAST_MULTI_BUFFER_HPP
0012 
0013 #include <boost/beast/core/detail/config.hpp>
0014 #include <boost/beast/core/detail/allocator.hpp>
0015 #include <boost/asio/buffer.hpp>
0016 #include <boost/core/empty_value.hpp>
0017 #include <boost/intrusive/list.hpp>
0018 #include <boost/type_traits/type_with_alignment.hpp>
0019 #include <iterator>
0020 #include <limits>
0021 #include <memory>
0022 #include <type_traits>
0023 
0024 namespace boost {
0025 namespace beast {
0026 
0027 /** A dynamic buffer providing sequences of variable length.
0028 
0029     A dynamic buffer encapsulates memory storage that may be
0030     automatically resized as required, where the memory is
0031     divided into two regions: readable bytes followed by
0032     writable bytes. These memory regions are internal to
0033     the dynamic buffer, but direct access to the elements
0034     is provided to permit them to be efficiently used with
0035     I/O operations.
0036 
0037     The implementation uses a sequence of one or more byte
0038     arrays of varying sizes to represent the readable and
0039     writable bytes. Additional byte array objects are
0040     appended to the sequence to accommodate changes in the
0041     desired size. The behavior and implementation of this
0042     container is most similar to `std::deque`.
0043 
0044     Objects of this type meet the requirements of <em>DynamicBuffer</em>
0045     and have the following additional properties:
0046 
0047     @li A mutable buffer sequence representing the readable
0048     bytes is returned by @ref data when `this` is non-const.
0049 
0050     @li Buffer sequences representing the readable and writable
0051     bytes, returned by @ref data and @ref prepare, may have
0052     length greater than one.
0053 
0054     @li A configurable maximum size may be set upon construction
0055     and adjusted afterwards. Calls to @ref prepare that would
0056     exceed this size will throw `std::length_error`.
0057 
0058     @li Sequences previously obtained using @ref data remain
0059     valid after calls to @ref prepare or @ref commit.
0060 
0061     @tparam Allocator The allocator to use for managing memory.
0062 */
0063 template<class Allocator>
0064 class basic_multi_buffer
0065 #if ! BOOST_BEAST_DOXYGEN
0066     : private boost::empty_value<Allocator>
0067 #endif
0068 {
0069     // Fancy pointers are not supported
0070     static_assert(std::is_pointer<typename
0071         std::allocator_traits<Allocator>::pointer>::value,
0072         "Allocator must use regular pointers");
0073 
0074     static bool constexpr default_nothrow =
0075         std::is_nothrow_default_constructible<Allocator>::value;
0076 
0077     // Storage for the list of buffers representing the input
0078     // and output sequences. The allocation for each element
0079     // contains `element` followed by raw storage bytes.
0080     class element
0081         : public boost::intrusive::list_base_hook<
0082             boost::intrusive::link_mode<
0083                 boost::intrusive::normal_link>>
0084     {
0085         using size_type = typename
0086             detail::allocator_traits<Allocator>::size_type;
0087 
0088         size_type const size_;
0089 
0090     public:
0091         element(element const&) = delete;
0092 
0093         explicit
0094         element(size_type n) noexcept
0095             : size_(n)
0096         {
0097         }
0098 
0099         size_type
0100         size() const noexcept
0101         {
0102             return size_;
0103         }
0104 
0105         char*
0106         data() const noexcept
0107         {
0108             return const_cast<char*>(
0109                 reinterpret_cast<char const*>(this + 1));
0110         }
0111     };
0112 
0113     template<bool>
0114     class subrange;
0115 
0116     using size_type = typename
0117         detail::allocator_traits<Allocator>::size_type;
0118 
0119     using align_type = typename
0120         boost::type_with_alignment<alignof(element)>::type;
0121 
0122     using rebind_type = typename
0123         beast::detail::allocator_traits<Allocator>::
0124             template rebind_alloc<align_type>;
0125 
0126     using alloc_traits =
0127         beast::detail::allocator_traits<rebind_type>;
0128 
0129     using list_type = typename boost::intrusive::make_list<
0130         element, boost::intrusive::constant_time_size<false>>::type;
0131 
0132     using iter = typename list_type::iterator;
0133 
0134     using const_iter = typename list_type::const_iterator;
0135 
0136     using pocma = typename
0137         alloc_traits::propagate_on_container_move_assignment;
0138 
0139     using pocca = typename
0140         alloc_traits::propagate_on_container_copy_assignment;
0141 
0142     static_assert(std::is_base_of<std::bidirectional_iterator_tag,
0143         typename std::iterator_traits<iter>::iterator_category>::value,
0144             "BidirectionalIterator type requirements not met");
0145 
0146     static_assert(std::is_base_of<std::bidirectional_iterator_tag,
0147         typename std::iterator_traits<const_iter>::iterator_category>::value,
0148             "BidirectionalIterator type requirements not met");
0149 
0150     std::size_t max_;
0151     list_type list_;        // list of allocated buffers
0152     iter out_;              // element that contains out_pos_
0153     size_type in_size_ = 0; // size of the input sequence
0154     size_type in_pos_ = 0;  // input offset in list_.front()
0155     size_type out_pos_ = 0; // output offset in *out_
0156     size_type out_end_ = 0; // output end offset in list_.back()
0157 
0158 public:
0159 #if BOOST_BEAST_DOXYGEN
0160     /// The ConstBufferSequence used to represent the readable bytes.
0161     using const_buffers_type = __implementation_defined__;
0162 
0163     /// The MutableBufferSequence used to represent the writable bytes.
0164     using mutable_buffers_type = __implementation_defined__;
0165 #else
0166     using const_buffers_type = subrange<false>;
0167 
0168     using mutable_buffers_type = subrange<true>;
0169 #endif
0170 
0171     /// The type of allocator used.
0172     using allocator_type = Allocator;
0173 
0174     /// Destructor
0175     ~basic_multi_buffer();
0176 
0177     /** Constructor
0178 
0179         After construction, @ref capacity will return zero, and
0180         @ref max_size will return the largest value which may
0181         be passed to the allocator's `allocate` function.
0182     */
0183     basic_multi_buffer() noexcept(default_nothrow);
0184 
0185     /** Constructor
0186 
0187         After construction, @ref capacity will return zero, and
0188         @ref max_size will return the specified value of `limit`.
0189 
0190         @param limit The desired maximum size.
0191     */
0192     explicit
0193     basic_multi_buffer(
0194         std::size_t limit) noexcept(default_nothrow);
0195 
0196     /** Constructor
0197 
0198         After construction, @ref capacity will return zero, and
0199         @ref max_size will return the largest value which may
0200         be passed to the allocator's `allocate` function.
0201 
0202         @param alloc The allocator to use for the object.
0203 
0204         @esafe
0205 
0206         No-throw guarantee.
0207     */
0208     explicit
0209     basic_multi_buffer(Allocator const& alloc) noexcept;
0210 
0211     /** Constructor
0212 
0213         After construction, @ref capacity will return zero, and
0214         @ref max_size will return the specified value of `limit`.
0215 
0216         @param limit The desired maximum size.
0217 
0218         @param alloc The allocator to use for the object.
0219 
0220         @esafe
0221 
0222         No-throw guarantee.
0223     */
0224     basic_multi_buffer(
0225         std::size_t limit, Allocator const& alloc) noexcept;
0226 
0227     /** Move Constructor
0228 
0229         The container is constructed with the contents of `other`
0230         using move semantics. The maximum size will be the same
0231         as the moved-from object.
0232 
0233         Buffer sequences previously obtained from `other` using
0234         @ref data or @ref prepare remain valid after the move.
0235 
0236         @param other The object to move from. After the move, the
0237         moved-from object will have zero capacity, zero readable
0238         bytes, and zero writable bytes.
0239 
0240         @esafe
0241 
0242         No-throw guarantee.
0243     */
0244     basic_multi_buffer(basic_multi_buffer&& other) noexcept;
0245 
0246     /** Move Constructor
0247 
0248         Using `alloc` as the allocator for the new container, the
0249         contents of `other` are moved. If `alloc != other.get_allocator()`,
0250         this results in a copy. The maximum size will be the same
0251         as the moved-from object.
0252 
0253         Buffer sequences previously obtained from `other` using
0254         @ref data or @ref prepare become invalid after the move.
0255 
0256         @param other The object to move from. After the move,
0257         the moved-from object will have zero capacity, zero readable
0258         bytes, and zero writable bytes.
0259 
0260         @param alloc The allocator to use for the object.
0261 
0262         @throws std::length_error if `other.size()` exceeds the
0263         maximum allocation size of `alloc`.
0264     */
0265     basic_multi_buffer(
0266         basic_multi_buffer&& other,
0267         Allocator const& alloc);
0268 
0269     /** Copy Constructor
0270 
0271         This container is constructed with the contents of `other`
0272         using copy semantics. The maximum size will be the same
0273         as the copied object.
0274 
0275         @param other The object to copy from.
0276 
0277         @throws std::length_error if `other.size()` exceeds the
0278         maximum allocation size of the allocator.
0279     */
0280     basic_multi_buffer(basic_multi_buffer const& other);
0281 
0282     /** Copy Constructor
0283 
0284         This container is constructed with the contents of `other`
0285         using copy semantics and the specified allocator. The maximum
0286         size will be the same as the copied object.
0287 
0288         @param other The object to copy from.
0289 
0290         @param alloc The allocator to use for the object.
0291 
0292         @throws std::length_error if `other.size()` exceeds the
0293         maximum allocation size of `alloc`.
0294     */
0295     basic_multi_buffer(basic_multi_buffer const& other,
0296         Allocator const& alloc);
0297 
0298     /** Copy Constructor
0299 
0300         This container is constructed with the contents of `other`
0301         using copy semantics. The maximum size will be the same
0302         as the copied object.
0303 
0304         @param other The object to copy from.
0305 
0306         @throws std::length_error if `other.size()` exceeds the
0307         maximum allocation size of the allocator.
0308     */
0309     template<class OtherAlloc>
0310     basic_multi_buffer(basic_multi_buffer<
0311         OtherAlloc> const& other);
0312 
0313     /** Copy Constructor
0314 
0315         This container is constructed with the contents of `other`
0316         using copy semantics. The maximum size will be the same
0317         as the copied object.
0318 
0319         @param other The object to copy from.
0320 
0321         @param alloc The allocator to use for the object.
0322 
0323         @throws std::length_error if `other.size()` exceeds the
0324         maximum allocation size of `alloc`.
0325     */
0326     template<class OtherAlloc>
0327     basic_multi_buffer(
0328         basic_multi_buffer<OtherAlloc> const& other,
0329         allocator_type const& alloc);
0330 
0331     /** Move Assignment
0332 
0333         The container is assigned with the contents of `other`
0334         using move semantics. The maximum size will be the same
0335         as the moved-from object.
0336 
0337         Buffer sequences previously obtained from `other` using
0338         @ref data or @ref prepare remain valid after the move.
0339 
0340         @param other The object to move from. After the move,
0341         the moved-from object will have zero capacity, zero readable
0342         bytes, and zero writable bytes.
0343     */
0344     basic_multi_buffer&
0345     operator=(basic_multi_buffer&& other);
0346 
0347     /** Copy Assignment
0348 
0349         The container is assigned with the contents of `other`
0350         using copy semantics. The maximum size will be the same
0351         as the copied object.
0352 
0353         After the copy, `this` will have zero writable bytes.
0354 
0355         @param other The object to copy from.
0356 
0357         @throws std::length_error if `other.size()` exceeds the
0358         maximum allocation size of the allocator.
0359     */
0360     basic_multi_buffer& operator=(
0361         basic_multi_buffer const& other);
0362 
0363     /** Copy Assignment
0364 
0365         The container is assigned with the contents of `other`
0366         using copy semantics. The maximum size will be the same
0367         as the copied object.
0368 
0369         After the copy, `this` will have zero writable bytes.
0370 
0371         @param other The object to copy from.
0372 
0373         @throws std::length_error if `other.size()` exceeds the
0374         maximum allocation size of the allocator.
0375     */
0376     template<class OtherAlloc>
0377     basic_multi_buffer& operator=(
0378         basic_multi_buffer<OtherAlloc> const& other);
0379 
0380     /// Returns a copy of the allocator used.
0381     allocator_type
0382     get_allocator() const
0383     {
0384         return this->get();
0385     }
0386 
0387     /** Set the maximum allowed capacity
0388 
0389         This function changes the currently configured upper limit
0390         on capacity to the specified value.
0391 
0392         @param n The maximum number of bytes ever allowed for capacity.
0393 
0394         @esafe
0395 
0396         No-throw guarantee.
0397     */
0398     void
0399     max_size(std::size_t n) noexcept
0400     {
0401         max_ = n;
0402     }
0403 
0404     /** Guarantee a minimum capacity
0405 
0406         This function adjusts the internal storage (if necessary)
0407         to guarantee space for at least `n` bytes.
0408 
0409         Buffer sequences previously obtained using @ref data remain
0410         valid, while buffer sequences previously obtained using
0411         @ref prepare become invalid.
0412 
0413         @param n The minimum number of byte for the new capacity.
0414         If this value is greater than the maximum size, then the
0415         maximum size will be adjusted upwards to this value.
0416 
0417         @throws std::length_error if n is larger than the maximum
0418         allocation size of the allocator.
0419 
0420         @esafe
0421 
0422         Strong guarantee.
0423     */
0424     void
0425     reserve(std::size_t n);
0426 
0427     /** Reallocate the buffer to fit the readable bytes exactly.
0428 
0429         Buffer sequences previously obtained using @ref data or
0430         @ref prepare become invalid.
0431 
0432         @esafe
0433 
0434         Strong guarantee.
0435     */
0436     void
0437     shrink_to_fit();
0438 
0439     /** Set the size of the readable and writable bytes to zero.
0440 
0441         This clears the buffer without changing capacity.
0442         Buffer sequences previously obtained using @ref data or
0443         @ref prepare become invalid.
0444 
0445         @esafe
0446 
0447         No-throw guarantee.
0448     */
0449     void
0450     clear() noexcept;
0451 
0452     /// Exchange two dynamic buffers
0453     template<class Alloc>
0454     friend
0455     void
0456     swap(
0457         basic_multi_buffer<Alloc>& lhs,
0458         basic_multi_buffer<Alloc>& rhs) noexcept;
0459 
0460     //--------------------------------------------------------------------------
0461 
0462     /// Returns the number of readable bytes.
0463     size_type
0464     size() const noexcept
0465     {
0466         return in_size_;
0467     }
0468 
0469     /// Return the maximum number of bytes, both readable and writable, that can ever be held.
0470     size_type
0471     max_size() const noexcept
0472     {
0473         return max_;
0474     }
0475 
0476     /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
0477     std::size_t
0478     capacity() const noexcept;
0479 
0480     /** Returns a constant buffer sequence representing the readable bytes
0481 
0482         @note The sequence may contain multiple contiguous memory regions.
0483     */
0484     const_buffers_type
0485     data() const noexcept;
0486 
0487     /** Returns a constant buffer sequence representing the readable bytes
0488 
0489         @note The sequence may contain multiple contiguous memory regions.
0490     */
0491     const_buffers_type
0492     cdata() const noexcept
0493     {
0494         return data();
0495     }
0496 
0497     /** Returns a mutable buffer sequence representing the readable bytes.
0498 
0499         @note The sequence may contain multiple contiguous memory regions.
0500     */
0501     mutable_buffers_type
0502     data() noexcept;
0503 
0504     /** Returns a mutable buffer sequence representing writable bytes.
0505     
0506         Returns a mutable buffer sequence representing the writable
0507         bytes containing exactly `n` bytes of storage. Memory may be
0508         reallocated as needed.
0509 
0510         All buffer sequences previously obtained using @ref prepare are
0511         invalidated. Buffer sequences previously obtained using @ref data
0512         remain valid.
0513 
0514         @param n The desired number of bytes in the returned buffer
0515         sequence.
0516 
0517         @throws std::length_error if `size() + n` exceeds `max_size()`.
0518 
0519         @esafe
0520 
0521         Strong guarantee.
0522     */
0523     mutable_buffers_type
0524     prepare(size_type n);
0525 
0526     /** Append writable bytes to the readable bytes.
0527 
0528         Appends n bytes from the start of the writable bytes to the
0529         end of the readable bytes. The remainder of the writable bytes
0530         are discarded. If n is greater than the number of writable
0531         bytes, all writable bytes are appended to the readable bytes.
0532 
0533         All buffer sequences previously obtained using @ref prepare are
0534         invalidated. Buffer sequences previously obtained using @ref data
0535         remain valid.
0536 
0537         @param n The number of bytes to append. If this number
0538         is greater than the number of writable bytes, all
0539         writable bytes are appended.
0540 
0541         @esafe
0542 
0543         No-throw guarantee.
0544     */
0545     void
0546     commit(size_type n) noexcept;
0547 
0548     /** Remove bytes from beginning of the readable bytes.
0549 
0550         Removes n bytes from the beginning of the readable bytes.
0551 
0552         All buffers sequences previously obtained using
0553         @ref data or @ref prepare are invalidated.
0554 
0555         @param n The number of bytes to remove. If this number
0556         is greater than the number of readable bytes, all
0557         readable bytes are removed.
0558 
0559         @esafe
0560 
0561         No-throw guarantee.
0562     */
0563     void
0564     consume(size_type n) noexcept;
0565 
0566 private:
0567     template<class OtherAlloc>
0568     friend class basic_multi_buffer;
0569 
0570     template<class OtherAlloc>
0571     void copy_from(basic_multi_buffer<OtherAlloc> const&);
0572     void move_assign(basic_multi_buffer& other, std::false_type);
0573     void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
0574     void copy_assign(basic_multi_buffer const& other, std::false_type);
0575     void copy_assign(basic_multi_buffer const& other, std::true_type);
0576     void swap(basic_multi_buffer&) noexcept;
0577     void swap(basic_multi_buffer&, std::true_type) noexcept;
0578     void swap(basic_multi_buffer&, std::false_type) noexcept;
0579     void destroy(list_type& list) noexcept;
0580     void destroy(const_iter it);
0581     void destroy(element& e);
0582     element& alloc(std::size_t size);
0583     void debug_check() const;
0584 };
0585 
0586 /// A typical multi buffer
0587 using multi_buffer = basic_multi_buffer<std::allocator<char>>;
0588 
0589 } // beast
0590 } // boost
0591 
0592 #include <boost/beast/core/impl/multi_buffer.hpp>
0593 
0594 #endif