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  
    /// Destroy the buffer.
85  
    ~basic_vector_dynamic_buffer() = default;
85  
    ~basic_vector_dynamic_buffer() = default;
86  

86  

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

98  

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

100  

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

120  

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

124  

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

131  

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

138  

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

147  

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

155  

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

157  

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

160  

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

162  

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

164  

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

172  

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

179  

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

181  

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

185  

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

200  

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

202  

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

206  

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

226  

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

230  

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

232  

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

247  

248  
} // capy
248  
} // capy
249  
} // boost
249  
} // boost
250  

250  

251  
#endif
251  
#endif