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  
    /** Construct a copy.
74  

74  

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

78  

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

83  

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

85  

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

97  

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

99  

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

104  

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

119  

120  
    /** Assign by copying.
120  
    /** Assign by copying.
121  

121  

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

125  

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

130  

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

137  

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

144  

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

151  

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

156  

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

158  

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

161  

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

163  

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

165  

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

171  

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

173  

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

177  

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

185  

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

187  

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

191  

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

199  

200  
} // capy
200  
} // capy
201  
} // boost
201  
} // boost
202  

202  

203  
#endif
203  
#endif