1  
//
1  
//
2  
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/capy
7  
// Official repository: https://github.com/cppalliance/capy
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_VECTOR_DYNAMIC_BUFFER_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/buffers.hpp>
14  
#include <boost/capy/buffers.hpp>
15  
#include <boost/capy/detail/except.hpp>
15  
#include <boost/capy/detail/except.hpp>
16  
#include <type_traits>
16  
#include <type_traits>
17  
#include <vector>
17  
#include <vector>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace capy {
20  
namespace capy {
21  

21  

22  
/** A dynamic buffer using an underlying vector.
22  
/** A dynamic buffer using an underlying vector.
23  

23  

24  
    This class adapts a `std::vector` of byte-sized elements
24  
    This class adapts a `std::vector` of byte-sized elements
25  
    to satisfy the DynamicBuffer concept. The vector provides
25  
    to satisfy the DynamicBuffer concept. The vector provides
26  
    automatic memory management and growth.
26  
    automatic memory management and growth.
27  

27  

28  
    @par Constraints
28  
    @par Constraints
29  

29  

30  
    The element type `T` must be a fundamental type with
30  
    The element type `T` must be a fundamental type with
31  
    `sizeof( T ) == 1`. This includes `char`, `unsigned char`,
31  
    `sizeof( T ) == 1`. This includes `char`, `unsigned char`,
32  
    `signed char`, and similar byte-sized fundamental types.
32  
    `signed char`, and similar byte-sized fundamental types.
33  

33  

34  
    @par Example
34  
    @par Example
35  
    @code
35  
    @code
36  
    std::vector<unsigned char> v;
36  
    std::vector<unsigned char> v;
37  
    vector_dynamic_buffer vb( &v );
37  
    vector_dynamic_buffer vb( &v );
38  

38  

39  
    // Write data
39  
    // Write data
40  
    auto mb = vb.prepare( 100 );
40  
    auto mb = vb.prepare( 100 );
41  
    std::memcpy( mb.data(), "hello", 5 );
41  
    std::memcpy( mb.data(), "hello", 5 );
42  
    vb.commit( 5 );
42  
    vb.commit( 5 );
43  

43  

44  
    // Read data
44  
    // Read data
45  
    auto data = vb.data();
45  
    auto data = vb.data();
46  
    // process data...
46  
    // process data...
47  
    vb.consume( 5 );
47  
    vb.consume( 5 );
48  
    @endcode
48  
    @endcode
49  

49  

50  
    @par Thread Safety
50  
    @par Thread Safety
51  
    Distinct objects: Safe.
51  
    Distinct objects: Safe.
52  
    Shared objects: Unsafe.
52  
    Shared objects: Unsafe.
53  

53  

54  
    @tparam T The element type. Must be fundamental with sizeof 1.
54  
    @tparam T The element type. Must be fundamental with sizeof 1.
55  
    @tparam Allocator The allocator type for the vector.
55  
    @tparam Allocator The allocator type for the vector.
56  

56  

57  
    @see flat_dynamic_buffer, circular_dynamic_buffer, string_dynamic_buffer
57  
    @see flat_dynamic_buffer, circular_dynamic_buffer, string_dynamic_buffer
58  
*/
58  
*/
59  
template<
59  
template<
60  
    class T,
60  
    class T,
61  
    class Allocator = std::allocator<T>>
61  
    class Allocator = std::allocator<T>>
62  
    requires std::is_fundamental_v<T> && (sizeof(T) == 1)
62  
    requires std::is_fundamental_v<T> && (sizeof(T) == 1)
63  
class basic_vector_dynamic_buffer
63  
class basic_vector_dynamic_buffer
64  
{
64  
{
65  
    std::vector<T, Allocator>* v_;
65  
    std::vector<T, Allocator>* v_;
66  
    std::size_t max_size_;
66  
    std::size_t max_size_;
67  

67  

68  
    std::size_t in_size_ = 0;
68  
    std::size_t in_size_ = 0;
69  
    std::size_t out_size_ = 0;
69  
    std::size_t out_size_ = 0;
70  

70  

71  
public:
71  
public:
72  
    /// Indicates this is a DynamicBuffer adapter over external storage.
72  
    /// Indicates this is a DynamicBuffer adapter over external storage.
73  
    using is_dynamic_buffer_adapter = void;
73  
    using is_dynamic_buffer_adapter = void;
74  

74  

75  
    /// The underlying vector type.
75  
    /// The underlying vector type.
76  
    using vector_type = std::vector<T, Allocator>;
76  
    using vector_type = std::vector<T, Allocator>;
77  

77  

78  
    /// The ConstBufferSequence type for readable bytes.
78  
    /// The ConstBufferSequence type for readable bytes.
79  
    using const_buffers_type = const_buffer;
79  
    using const_buffers_type = const_buffer;
80  

80  

81  
    /// The MutableBufferSequence type for writable bytes.
81  
    /// The MutableBufferSequence type for writable bytes.
82  
    using mutable_buffers_type = mutable_buffer;
82  
    using mutable_buffers_type = mutable_buffer;
83  

83  

 
84 +
    /// Destroy the buffer.
84  
    ~basic_vector_dynamic_buffer() = default;
85  
    ~basic_vector_dynamic_buffer() = default;
85  

86  

86 -
    /** Move constructor.
87 +
    /** Construct by moving.
87  
    */
88  
    */
88  
    basic_vector_dynamic_buffer(
89  
    basic_vector_dynamic_buffer(
89  
        basic_vector_dynamic_buffer&& other) noexcept
90  
        basic_vector_dynamic_buffer&& other) noexcept
90  
        : v_(other.v_)
91  
        : v_(other.v_)
91  
        , max_size_(other.max_size_)
92  
        , max_size_(other.max_size_)
92  
        , in_size_(other.in_size_)
93  
        , in_size_(other.in_size_)
93  
        , out_size_(other.out_size_)
94  
        , out_size_(other.out_size_)
94  
    {
95  
    {
95  
        other.v_ = nullptr;
96  
        other.v_ = nullptr;
96  
    }
97  
    }
97  

98  

98  
    /** Construct a dynamic buffer over a vector.
99  
    /** Construct a dynamic buffer over a vector.
99  

100  

100  
        @param v Pointer to the vector to use as storage.
101  
        @param v Pointer to the vector to use as storage.
101  
        @param max_size Optional maximum size limit. Defaults
102  
        @param max_size Optional maximum size limit. Defaults
102  
            to the vector's `max_size()`.
103  
            to the vector's `max_size()`.
103  
    */
104  
    */
104  
    explicit
105  
    explicit
105  
    basic_vector_dynamic_buffer(
106  
    basic_vector_dynamic_buffer(
106  
        vector_type* v,
107  
        vector_type* v,
107  
        std::size_t max_size =
108  
        std::size_t max_size =
108  
            std::size_t(-1)) noexcept
109  
            std::size_t(-1)) noexcept
109  
        : v_(v)
110  
        : v_(v)
110  
        , max_size_(
111  
        , max_size_(
111  
            max_size > v_->max_size()
112  
            max_size > v_->max_size()
112  
                ? v_->max_size()
113  
                ? v_->max_size()
113  
                : max_size)
114  
                : max_size)
114  
    {
115  
    {
115  
        if(v_->size() > max_size_)
116  
        if(v_->size() > max_size_)
116  
            v_->resize(max_size_);
117  
            v_->resize(max_size_);
117  
        in_size_ = v_->size();
118  
        in_size_ = v_->size();
118  
    }
119  
    }
119  

120  

120  
    /// Copy assignment is deleted.
121  
    /// Copy assignment is deleted.
121  
    basic_vector_dynamic_buffer& operator=(
122  
    basic_vector_dynamic_buffer& operator=(
122  
        basic_vector_dynamic_buffer const&) = delete;
123  
        basic_vector_dynamic_buffer const&) = delete;
123  

124  

124  
    /// Return the number of readable bytes.
125  
    /// Return the number of readable bytes.
125  
    std::size_t
126  
    std::size_t
126  
    size() const noexcept
127  
    size() const noexcept
127  
    {
128  
    {
128  
        return in_size_;
129  
        return in_size_;
129  
    }
130  
    }
130  

131  

131  
    /// Return the maximum number of bytes the buffer can hold.
132  
    /// Return the maximum number of bytes the buffer can hold.
132  
    std::size_t
133  
    std::size_t
133  
    max_size() const noexcept
134  
    max_size() const noexcept
134  
    {
135  
    {
135  
        return max_size_;
136  
        return max_size_;
136  
    }
137  
    }
137  

138  

138  
    /// Return the number of writable bytes without reallocation.
139  
    /// Return the number of writable bytes without reallocation.
139  
    std::size_t
140  
    std::size_t
140  
    capacity() const noexcept
141  
    capacity() const noexcept
141  
    {
142  
    {
142  
        if(v_->capacity() <= max_size_)
143  
        if(v_->capacity() <= max_size_)
143  
            return v_->capacity() - in_size_;
144  
            return v_->capacity() - in_size_;
144  
        return max_size_ - in_size_;
145  
        return max_size_ - in_size_;
145  
    }
146  
    }
146  

147  

147  
    /// Return a buffer sequence representing the readable bytes.
148  
    /// Return a buffer sequence representing the readable bytes.
148  
    const_buffers_type
149  
    const_buffers_type
149  
    data() const noexcept
150  
    data() const noexcept
150  
    {
151  
    {
151  
        return const_buffers_type(
152  
        return const_buffers_type(
152  
            v_->data(), in_size_);
153  
            v_->data(), in_size_);
153  
    }
154  
    }
154  

155  

155  
    /** Return a buffer sequence for writing.
156  
    /** Return a buffer sequence for writing.
156  

157  

157  
        Invalidates buffer sequences previously obtained
158  
        Invalidates buffer sequences previously obtained
158  
        from @ref prepare.
159  
        from @ref prepare.
159  

160  

160  
        @param n The desired number of writable bytes.
161  
        @param n The desired number of writable bytes.
161  

162  

162  
        @return A mutable buffer sequence of size @p n.
163  
        @return A mutable buffer sequence of size @p n.
163  

164  

164  
        @throws std::invalid_argument if `size() + n > max_size()`.
165  
        @throws std::invalid_argument if `size() + n > max_size()`.
165  
    */
166  
    */
166  
    mutable_buffers_type
167  
    mutable_buffers_type
167  
    prepare(std::size_t n)
168  
    prepare(std::size_t n)
168  
    {
169  
    {
169  
        if(n > max_size_ - in_size_)
170  
        if(n > max_size_ - in_size_)
170  
            detail::throw_invalid_argument();
171  
            detail::throw_invalid_argument();
171  

172  

172  
        if(v_->size() < in_size_ + n)
173  
        if(v_->size() < in_size_ + n)
173  
            v_->resize(in_size_ + n);
174  
            v_->resize(in_size_ + n);
174  
        out_size_ = n;
175  
        out_size_ = n;
175  
        return mutable_buffers_type(
176  
        return mutable_buffers_type(
176  
            v_->data() + in_size_, out_size_);
177  
            v_->data() + in_size_, out_size_);
177  
    }
178  
    }
178  

179  

179  
    /** Move bytes from the output to the input sequence.
180  
    /** Move bytes from the output to the input sequence.
180  

181  

181  
        Invalidates buffer sequences previously obtained
182  
        Invalidates buffer sequences previously obtained
182  
        from @ref prepare. Buffer sequences from @ref data
183  
        from @ref prepare. Buffer sequences from @ref data
183  
        remain valid.
184  
        remain valid.
184  

185  

185  
        @param n The number of bytes to commit. If greater
186  
        @param n The number of bytes to commit. If greater
186  
            than the prepared size, all prepared bytes
187  
            than the prepared size, all prepared bytes
187  
            are committed.
188  
            are committed.
188  
    */
189  
    */
189  
    void
190  
    void
190  
    commit(std::size_t n) noexcept
191  
    commit(std::size_t n) noexcept
191  
    {
192  
    {
192  
        if(n < out_size_)
193  
        if(n < out_size_)
193  
            in_size_ += n;
194  
            in_size_ += n;
194  
        else
195  
        else
195  
            in_size_ += out_size_;
196  
            in_size_ += out_size_;
196  
        out_size_ = 0;
197  
        out_size_ = 0;
197  
        v_->resize(in_size_);
198  
        v_->resize(in_size_);
198  
    }
199  
    }
199  

200  

200  
    /** Remove bytes from the beginning of the input sequence.
201  
    /** Remove bytes from the beginning of the input sequence.
201  

202  

202  
        Invalidates buffer sequences previously obtained
203  
        Invalidates buffer sequences previously obtained
203  
        from @ref data. Buffer sequences from @ref prepare
204  
        from @ref data. Buffer sequences from @ref prepare
204  
        remain valid.
205  
        remain valid.
205  

206  

206  
        @param n The number of bytes to consume. If greater
207  
        @param n The number of bytes to consume. If greater
207  
            than @ref size(), all readable bytes are consumed.
208  
            than @ref size(), all readable bytes are consumed.
208  
    */
209  
    */
209  
    void
210  
    void
210  
    consume(std::size_t n) noexcept
211  
    consume(std::size_t n) noexcept
211  
    {
212  
    {
212  
        if(n < in_size_)
213  
        if(n < in_size_)
213  
        {
214  
        {
214  
            v_->erase(v_->begin(), v_->begin() + n);
215  
            v_->erase(v_->begin(), v_->begin() + n);
215  
            in_size_ -= n;
216  
            in_size_ -= n;
216  
        }
217  
        }
217  
        else
218  
        else
218  
        {
219  
        {
219  
            v_->clear();
220  
            v_->clear();
220  
            in_size_ = 0;
221  
            in_size_ = 0;
221  
        }
222  
        }
222  
        out_size_ = 0;
223  
        out_size_ = 0;
223  
    }
224  
    }
224  
};
225  
};
225  

226  

226  
/// A dynamic buffer using `std::vector<unsigned char>`.
227  
/// A dynamic buffer using `std::vector<unsigned char>`.
227  
using vector_dynamic_buffer =
228  
using vector_dynamic_buffer =
228  
    basic_vector_dynamic_buffer<unsigned char>;
229  
    basic_vector_dynamic_buffer<unsigned char>;
229  

230  

230  
/** Create a dynamic buffer from a vector.
231  
/** Create a dynamic buffer from a vector.
231  

232  

232  
    @param v The vector to wrap. Element type must be
233  
    @param v The vector to wrap. Element type must be
233  
        a fundamental type with sizeof 1.
234  
        a fundamental type with sizeof 1.
234  
    @param max_size Optional maximum size limit.
235  
    @param max_size Optional maximum size limit.
235  
    @return A vector_dynamic_buffer wrapping the vector.
236  
    @return A vector_dynamic_buffer wrapping the vector.
236  
*/
237  
*/
237  
template<class T, class Allocator>
238  
template<class T, class Allocator>
238  
    requires std::is_fundamental_v<T> && (sizeof(T) == 1)
239  
    requires std::is_fundamental_v<T> && (sizeof(T) == 1)
239  
basic_vector_dynamic_buffer<T, Allocator>
240  
basic_vector_dynamic_buffer<T, Allocator>
240  
dynamic_buffer(
241  
dynamic_buffer(
241  
    std::vector<T, Allocator>& v,
242  
    std::vector<T, Allocator>& v,
242  
    std::size_t max_size = std::size_t(-1))
243  
    std::size_t max_size = std::size_t(-1))
243  
{
244  
{
244  
    return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
245  
    return basic_vector_dynamic_buffer<T, Allocator>(&v, max_size);
245  
}
246  
}
246  

247  

247  
} // capy
248  
} // capy
248  
} // boost
249  
} // boost
249  

250  

250  
#endif
251  
#endif