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 -
    /// Destroy the buffer.
 
84  

83  

85  
    ~basic_vector_dynamic_buffer() = default;
84  
    ~basic_vector_dynamic_buffer() = default;
86  

85  

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

97  

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

99  

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

119  

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

123  

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

130  

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

137  

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

146  

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

154  

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

156  

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

159  

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

161  

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

163  

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

171  

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

178  

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

180  

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

184  

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

199  

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

201  

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

205  

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

225  

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

229  

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

231  

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

246  

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

249  

251  
#endif
250  
#endif