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  
    /// Copy constructor.
74  
    circular_dynamic_buffer(
74  
    circular_dynamic_buffer(
75  
        circular_dynamic_buffer const&) = default;
75  
        circular_dynamic_buffer const&) = default;
76  

76  

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

78  

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

90  

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

92  

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

97  

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

112  

113  
    /// Copy assignment.
113  
    /// Copy assignment.
114  
    circular_dynamic_buffer& operator=(
114  
    circular_dynamic_buffer& operator=(
115  
        circular_dynamic_buffer const&) = default;
115  
        circular_dynamic_buffer const&) = default;
116  

116  

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

123  

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

130  

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

137  

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

142  

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

144  

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

147  

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

149  

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

151  

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

157  

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

159  

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

163  

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

171  

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

173  

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

177  

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

185  

186  
} // capy
186  
} // capy
187  
} // boost
187  
} // boost
188  

188  

189  
#endif
189  
#endif