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 -
    /** Construct a copy.
73 +
    /// Copy constructor.
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 -
    */
 
81  
    circular_dynamic_buffer(
74  
    circular_dynamic_buffer(
82  
        circular_dynamic_buffer const&) = default;
75  
        circular_dynamic_buffer const&) = default;
83  

76  

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

78  

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

90  

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

92  

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

97  

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

112  

120 -
    /** Assign by copying.
113 +
    /// Copy assignment.
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 -
    */
 
128  
    circular_dynamic_buffer& operator=(
114  
    circular_dynamic_buffer& operator=(
129  
        circular_dynamic_buffer const&) = default;
115  
        circular_dynamic_buffer const&) = default;
130  

116  

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

123  

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

130  

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

137  

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

142  

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

144  

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

147  

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

149  

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

151  

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

157  

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

159  

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

163  

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

171  

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

173  

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

177  

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

185  

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

188  

203  
#endif
189  
#endif