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_CIRCULAR_DYNAMIC_BUFFER_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_CIRCULAR_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_CIRCULAR_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_CIRCULAR_DYNAMIC_BUFFER_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/buffers/buffer_pair.hpp>
14  
#include <boost/capy/buffers/buffer_pair.hpp>
15  
#include <boost/capy/detail/except.hpp>
15  
#include <boost/capy/detail/except.hpp>
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace capy {
18  
namespace capy {
19  

19  

20  
/** A fixed-capacity circular buffer satisfying DynamicBuffer.
20  
/** A fixed-capacity circular buffer satisfying DynamicBuffer.
21  

21  

22  
    This class implements a circular ( ring ) buffer with
22  
    This class implements a circular ( ring ) buffer with
23  
    fixed capacity determined at construction. Unlike linear
23  
    fixed capacity determined at construction. Unlike linear
24  
    buffers, data can wrap around from the end to the beginning,
24  
    buffers, data can wrap around from the end to the beginning,
25  
    enabling efficient FIFO operations without memory copies.
25  
    enabling efficient FIFO operations without memory copies.
26  

26  

27  
    Buffer sequences returned from @ref data and @ref prepare
27  
    Buffer sequences returned from @ref data and @ref prepare
28  
    may contain up to two elements to represent wrapped regions.
28  
    may contain up to two elements to represent wrapped regions.
29  

29  

30  
    @par Example
30  
    @par Example
31  
    @code
31  
    @code
32  
    char storage[1024];
32  
    char storage[1024];
33  
    circular_dynamic_buffer cb( storage, sizeof( storage ) );
33  
    circular_dynamic_buffer cb( storage, sizeof( storage ) );
34  

34  

35  
    // Write data
35  
    // Write data
36  
    auto mb = cb.prepare( 100 );
36  
    auto mb = cb.prepare( 100 );
37  
    std::memcpy( mb.data(), "hello", 5 );
37  
    std::memcpy( mb.data(), "hello", 5 );
38  
    cb.commit( 5 );
38  
    cb.commit( 5 );
39  

39  

40  
    // Read data
40  
    // Read data
41  
    auto cb_data = cb.data();
41  
    auto cb_data = cb.data();
42  
    // process cb_data...
42  
    // process cb_data...
43  
    cb.consume( 5 );
43  
    cb.consume( 5 );
44  
    @endcode
44  
    @endcode
45  

45  

46  
    @par Thread Safety
46  
    @par Thread Safety
47  
    Distinct objects: Safe.
47  
    Distinct objects: Safe.
48  
    Shared objects: Unsafe.
48  
    Shared objects: Unsafe.
49  

49  

50  
    @see flat_dynamic_buffer, string_dynamic_buffer
50  
    @see flat_dynamic_buffer, string_dynamic_buffer
51  
*/
51  
*/
52  
class circular_dynamic_buffer
52  
class circular_dynamic_buffer
53  
{
53  
{
54  
    unsigned char* base_ = nullptr;
54  
    unsigned char* base_ = nullptr;
55  
    std::size_t cap_ = 0;
55  
    std::size_t cap_ = 0;
56  
    std::size_t in_pos_ = 0;
56  
    std::size_t in_pos_ = 0;
57  
    std::size_t in_len_ = 0;
57  
    std::size_t in_len_ = 0;
58  
    std::size_t out_size_ = 0;
58  
    std::size_t out_size_ = 0;
59  

59  

60  
public:
60  
public:
61  
    /// Indicates this is a DynamicBuffer adapter over external storage.
61  
    /// Indicates this is a DynamicBuffer adapter over external storage.
62  
    using is_dynamic_buffer_adapter = void;
62  
    using is_dynamic_buffer_adapter = void;
63  

63  

64  
    /// The ConstBufferSequence type for readable bytes.
64  
    /// The ConstBufferSequence type for readable bytes.
65  
    using const_buffers_type = const_buffer_pair;
65  
    using const_buffers_type = const_buffer_pair;
66  

66  

67  
    /// The MutableBufferSequence type for writable bytes.
67  
    /// The MutableBufferSequence type for writable bytes.
68  
    using mutable_buffers_type = mutable_buffer_pair;
68  
    using mutable_buffers_type = mutable_buffer_pair;
69  

69  

70  
    /// Construct an empty circular buffer with zero capacity.
70  
    /// Construct an empty circular buffer with zero capacity.
71  
    circular_dynamic_buffer() = default;
71  
    circular_dynamic_buffer() = default;
72  

72  

73 -
    /// Copy constructor.
73 +
    /** Construct a copy.
 
74 +

 
75 +
        Copies the adapter state (position and length) but does
 
76 +
        not deep-copy the backing storage. Both objects alias the
 
77 +
        same external buffer.
 
78 +

 
79 +
        @note The underlying storage must outlive all copies.
 
80 +
    */
74  
    circular_dynamic_buffer(
81  
    circular_dynamic_buffer(
75  
        circular_dynamic_buffer const&) = default;
82  
        circular_dynamic_buffer const&) = default;
76  

83  

77  
    /** Construct a circular buffer over existing storage.
84  
    /** Construct a circular buffer over existing storage.
78  

85  

79  
        @param base Pointer to the storage.
86  
        @param base Pointer to the storage.
80  
        @param capacity Size of the storage in bytes.
87  
        @param capacity Size of the storage in bytes.
81  
    */
88  
    */
82  
    circular_dynamic_buffer(
89  
    circular_dynamic_buffer(
83  
        void* base,
90  
        void* base,
84  
        std::size_t capacity) noexcept
91  
        std::size_t capacity) noexcept
85  
        : base_(static_cast<
92  
        : base_(static_cast<
86  
            unsigned char*>(base))
93  
            unsigned char*>(base))
87  
        , cap_(capacity)
94  
        , cap_(capacity)
88  
    {
95  
    {
89  
    }
96  
    }
90  

97  

91  
    /** Construct a circular buffer with initial readable bytes.
98  
    /** Construct a circular buffer with initial readable bytes.
92  

99  

93  
        @param base Pointer to the storage.
100  
        @param base Pointer to the storage.
94  
        @param capacity Size of the storage in bytes.
101  
        @param capacity Size of the storage in bytes.
95  
        @param initial_size Number of bytes already present as
102  
        @param initial_size Number of bytes already present as
96  
            readable. Must not exceed @p capacity.
103  
            readable. Must not exceed @p capacity.
97  

104  

98  
        @throws std::invalid_argument if initial_size > capacity.
105  
        @throws std::invalid_argument if initial_size > capacity.
99  
    */
106  
    */
100  
    circular_dynamic_buffer(
107  
    circular_dynamic_buffer(
101  
        void* base,
108  
        void* base,
102  
        std::size_t capacity,
109  
        std::size_t capacity,
103  
        std::size_t initial_size)
110  
        std::size_t initial_size)
104  
        : base_(static_cast<
111  
        : base_(static_cast<
105  
            unsigned char*>(base))
112  
            unsigned char*>(base))
106  
        , cap_(capacity)
113  
        , cap_(capacity)
107  
        , in_len_(initial_size)
114  
        , in_len_(initial_size)
108  
    {
115  
    {
109  
        if(in_len_ > capacity)
116  
        if(in_len_ > capacity)
110  
            detail::throw_invalid_argument();
117  
            detail::throw_invalid_argument();
111  
    }
118  
    }
112  

119  

113 -
    /// Copy assignment.
120 +
    /** Assign by copying.
 
121 +

 
122 +
        Copies the adapter state but does not deep-copy the
 
123 +
        backing storage. Both objects alias the same external
 
124 +
        buffer afterward.
 
125 +

 
126 +
        @note The underlying storage must outlive all copies.
 
127 +
    */
114  
    circular_dynamic_buffer& operator=(
128  
    circular_dynamic_buffer& operator=(
115  
        circular_dynamic_buffer const&) = default;
129  
        circular_dynamic_buffer const&) = default;
116  

130  

117  
    /// Return the number of readable bytes.
131  
    /// Return the number of readable bytes.
118  
    std::size_t
132  
    std::size_t
119  
    size() const noexcept
133  
    size() const noexcept
120  
    {
134  
    {
121  
        return in_len_;
135  
        return in_len_;
122  
    }
136  
    }
123  

137  

124  
    /// Return the maximum number of bytes the buffer can hold.
138  
    /// Return the maximum number of bytes the buffer can hold.
125  
    std::size_t
139  
    std::size_t
126  
    max_size() const noexcept
140  
    max_size() const noexcept
127  
    {
141  
    {
128  
        return cap_;
142  
        return cap_;
129  
    }
143  
    }
130  

144  

131  
    /// Return the number of writable bytes without reallocation.
145  
    /// Return the number of writable bytes without reallocation.
132  
    std::size_t
146  
    std::size_t
133  
    capacity() const noexcept
147  
    capacity() const noexcept
134  
    {
148  
    {
135  
        return cap_ - in_len_;
149  
        return cap_ - in_len_;
136  
    }
150  
    }
137  

151  

138  
    /// Return a buffer sequence representing the readable bytes.
152  
    /// Return a buffer sequence representing the readable bytes.
139  
    BOOST_CAPY_DECL
153  
    BOOST_CAPY_DECL
140  
    const_buffers_type
154  
    const_buffers_type
141  
    data() const noexcept;
155  
    data() const noexcept;
142  

156  

143  
    /** Return a buffer sequence for writing.
157  
    /** Return a buffer sequence for writing.
144  

158  

145  
        Invalidates buffer sequences previously obtained
159  
        Invalidates buffer sequences previously obtained
146  
        from @ref prepare.
160  
        from @ref prepare.
147  

161  

148  
        @param n The desired number of writable bytes.
162  
        @param n The desired number of writable bytes.
149  

163  

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

165  

152  
        @throws std::length_error if `size() + n > max_size()`.
166  
        @throws std::length_error if `size() + n > max_size()`.
153  
    */
167  
    */
154  
    BOOST_CAPY_DECL
168  
    BOOST_CAPY_DECL
155  
    mutable_buffers_type
169  
    mutable_buffers_type
156  
    prepare(std::size_t n);
170  
    prepare(std::size_t n);
157  

171  

158  
    /** Move bytes from the output to the input sequence.
172  
    /** Move bytes from the output to the input sequence.
159  

173  

160  
        Invalidates buffer sequences previously obtained
174  
        Invalidates buffer sequences previously obtained
161  
        from @ref prepare. Buffer sequences from @ref data
175  
        from @ref prepare. Buffer sequences from @ref data
162  
        remain valid.
176  
        remain valid.
163  

177  

164  
        @param n The number of bytes to commit. If greater
178  
        @param n The number of bytes to commit. If greater
165  
            than the prepared size, all prepared bytes
179  
            than the prepared size, all prepared bytes
166  
            are committed.
180  
            are committed.
167  
    */
181  
    */
168  
    BOOST_CAPY_DECL
182  
    BOOST_CAPY_DECL
169  
    void
183  
    void
170  
    commit(std::size_t n) noexcept;
184  
    commit(std::size_t n) noexcept;
171  

185  

172  
    /** Remove bytes from the beginning of the input sequence.
186  
    /** Remove bytes from the beginning of the input sequence.
173  

187  

174  
        Invalidates buffer sequences previously obtained
188  
        Invalidates buffer sequences previously obtained
175  
        from @ref data. Buffer sequences from @ref prepare
189  
        from @ref data. Buffer sequences from @ref prepare
176  
        remain valid.
190  
        remain valid.
177  

191  

178  
        @param n The number of bytes to consume. If greater
192  
        @param n The number of bytes to consume. If greater
179  
            than @ref size(), all readable bytes are consumed.
193  
            than @ref size(), all readable bytes are consumed.
180  
    */
194  
    */
181  
    BOOST_CAPY_DECL
195  
    BOOST_CAPY_DECL
182  
    void
196  
    void
183  
    consume(std::size_t n) noexcept;
197  
    consume(std::size_t n) noexcept;
184  
};
198  
};
185  

199  

186  
} // capy
200  
} // capy
187  
} // boost
201  
} // boost
188  

202  

189  
#endif
203  
#endif