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  
    ~basic_vector_dynamic_buffer() = default;
84  
    ~basic_vector_dynamic_buffer() = default;
85  

85  

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

97  

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

99  

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

119  

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

123  

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

130  

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

137  

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

146  

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

154  

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

156  

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

159  

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

161  

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

163  

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

171  

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

178  

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

180  

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

184  

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

199  

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

201  

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

205  

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

225  

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

229  

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

231  

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

246  

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

249  

250  
#endif
250  
#endif