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_FLAT_DYNAMIC_BUFFER_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_FLAT_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_FLAT_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_FLAT_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  

16  

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

19  

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

21  

22  
    This class provides a contiguous buffer with fixed capacity
22  
    This class provides a contiguous buffer with fixed capacity
23  
    determined at construction. Buffer sequences returned from
23  
    determined at construction. Buffer sequences returned from
24  
    @ref data and @ref prepare always contain exactly one element,
24  
    @ref data and @ref prepare always contain exactly one element,
25  
    making it suitable for APIs requiring contiguous memory.
25  
    making it suitable for APIs requiring contiguous memory.
26  

26  

27  
    @par Example
27  
    @par Example
28  
    @code
28  
    @code
29  
    char storage[1024];
29  
    char storage[1024];
30  
    flat_dynamic_buffer fb( storage, sizeof( storage ) );
30  
    flat_dynamic_buffer fb( storage, sizeof( storage ) );
31  

31  

32  
    // Write data
32  
    // Write data
33  
    auto mb = fb.prepare( 100 );
33  
    auto mb = fb.prepare( 100 );
34  
    std::memcpy( mb.data(), "hello", 5 );
34  
    std::memcpy( mb.data(), "hello", 5 );
35  
    fb.commit( 5 );
35  
    fb.commit( 5 );
36  

36  

37  
    // Read data
37  
    // Read data
38  
    auto data = fb.data();
38  
    auto data = fb.data();
39  
    // process data...
39  
    // process data...
40  
    fb.consume( 5 );
40  
    fb.consume( 5 );
41  
    @endcode
41  
    @endcode
42  

42  

43  
    @par Thread Safety
43  
    @par Thread Safety
44  
    Distinct objects: Safe.
44  
    Distinct objects: Safe.
45  
    Shared objects: Unsafe.
45  
    Shared objects: Unsafe.
46  

46  

47  
    @see circular_dynamic_buffer, string_dynamic_buffer
47  
    @see circular_dynamic_buffer, string_dynamic_buffer
48  
*/
48  
*/
49  
class flat_dynamic_buffer
49  
class flat_dynamic_buffer
50  
{
50  
{
51  
    unsigned char* data_ = nullptr;
51  
    unsigned char* data_ = nullptr;
52  
    std::size_t cap_ = 0;
52  
    std::size_t cap_ = 0;
53  
    std::size_t in_pos_ = 0;
53  
    std::size_t in_pos_ = 0;
54  
    std::size_t in_size_ = 0;
54  
    std::size_t in_size_ = 0;
55  
    std::size_t out_size_ = 0;
55  
    std::size_t out_size_ = 0;
56  

56  

57  
public:
57  
public:
58  
    /// Indicates this is a DynamicBuffer adapter over external storage.
58  
    /// Indicates this is a DynamicBuffer adapter over external storage.
59  
    using is_dynamic_buffer_adapter = void;
59  
    using is_dynamic_buffer_adapter = void;
60  

60  

61  
    /// The ConstBufferSequence type for readable bytes.
61  
    /// The ConstBufferSequence type for readable bytes.
62  
    using const_buffers_type = const_buffer;
62  
    using const_buffers_type = const_buffer;
63  

63  

64  
    /// The MutableBufferSequence type for writable bytes.
64  
    /// The MutableBufferSequence type for writable bytes.
65  
    using mutable_buffers_type = mutable_buffer;
65  
    using mutable_buffers_type = mutable_buffer;
66  

66  

67  
    /// Construct an empty flat buffer with zero capacity.
67  
    /// Construct an empty flat buffer with zero capacity.
68  
    flat_dynamic_buffer() = default;
68  
    flat_dynamic_buffer() = default;
69  

69  

70  
    /** Construct a flat buffer over existing storage.
70  
    /** Construct a flat buffer over existing storage.
71  

71  

72  
        @param data Pointer to the storage.
72  
        @param data Pointer to the storage.
73  
        @param capacity Size of the storage in bytes.
73  
        @param capacity Size of the storage in bytes.
74  
        @param initial_size Number of bytes already present as
74  
        @param initial_size Number of bytes already present as
75  
            readable. Must not exceed @p capacity.
75  
            readable. Must not exceed @p capacity.
76  

76  

77  
        @throws std::invalid_argument if initial_size > capacity.
77  
        @throws std::invalid_argument if initial_size > capacity.
78  
    */
78  
    */
79  
    flat_dynamic_buffer(
79  
    flat_dynamic_buffer(
80  
        void* data,
80  
        void* data,
81  
        std::size_t capacity,
81  
        std::size_t capacity,
82  
        std::size_t initial_size = 0)
82  
        std::size_t initial_size = 0)
83  
        : data_(static_cast<
83  
        : data_(static_cast<
84  
            unsigned char*>(data))
84  
            unsigned char*>(data))
85  
        , cap_(capacity)
85  
        , cap_(capacity)
86  
        , in_size_(initial_size)
86  
        , in_size_(initial_size)
87  
    {
87  
    {
88  
        if(in_size_ > cap_)
88  
        if(in_size_ > cap_)
89  
            detail::throw_invalid_argument();
89  
            detail::throw_invalid_argument();
90  
    }
90  
    }
91  

91  

92  
    /// Copy constructor.
92  
    /// Copy constructor.
93  
    flat_dynamic_buffer(
93  
    flat_dynamic_buffer(
94  
        flat_dynamic_buffer const&) = default;
94  
        flat_dynamic_buffer const&) = default;
95  

95  

96  
    /// Copy assignment.
96  
    /// Copy assignment.
97  
    flat_dynamic_buffer& operator=(
97  
    flat_dynamic_buffer& operator=(
98  
        flat_dynamic_buffer const&) = default;
98  
        flat_dynamic_buffer const&) = default;
99  

99  

100  
    /// Return the number of readable bytes.
100  
    /// Return the number of readable bytes.
101  
    std::size_t
101  
    std::size_t
102  
    size() const noexcept
102  
    size() const noexcept
103  
    {
103  
    {
104  
        return in_size_;
104  
        return in_size_;
105  
    }
105  
    }
106  

106  

107  
    /// Return the maximum number of bytes the buffer can hold.
107  
    /// Return the maximum number of bytes the buffer can hold.
108  
    std::size_t
108  
    std::size_t
109  
    max_size() const noexcept
109  
    max_size() const noexcept
110  
    {
110  
    {
111  
        return cap_;
111  
        return cap_;
112  
    }
112  
    }
113  

113  

114  
    /// Return the number of writable bytes without reallocation.
114  
    /// Return the number of writable bytes without reallocation.
115  
    std::size_t
115  
    std::size_t
116  
    capacity() const noexcept
116  
    capacity() const noexcept
117  
    {
117  
    {
118  
        return cap_ - (in_pos_ + in_size_);
118  
        return cap_ - (in_pos_ + in_size_);
119  
    }
119  
    }
120  

120  

121  
    /// Return a buffer sequence representing the readable bytes.
121  
    /// Return a buffer sequence representing the readable bytes.
122  
    const_buffers_type
122  
    const_buffers_type
123  
    data() const noexcept
123  
    data() const noexcept
124  
    {
124  
    {
125  
        return const_buffers_type(
125  
        return const_buffers_type(
126  
            data_ + in_pos_, in_size_);
126  
            data_ + in_pos_, in_size_);
127  
    }
127  
    }
128  

128  

129  
    /** Return a buffer sequence for writing.
129  
    /** Return a buffer sequence for writing.
130  

130  

131  
        Invalidates buffer sequences previously obtained
131  
        Invalidates buffer sequences previously obtained
132  
        from @ref prepare.
132  
        from @ref prepare.
133  

133  

134  
        @param n The desired number of writable bytes.
134  
        @param n The desired number of writable bytes.
135  

135  

136  
        @return A mutable buffer sequence of size @p n.
136  
        @return A mutable buffer sequence of size @p n.
137  

137  

138  
        @throws std::invalid_argument if `n > capacity()`.
138  
        @throws std::invalid_argument if `n > capacity()`.
139  
    */
139  
    */
140  
    mutable_buffers_type
140  
    mutable_buffers_type
141  
    prepare(std::size_t n)
141  
    prepare(std::size_t n)
142  
    {
142  
    {
143  
        if( n > capacity() )
143  
        if( n > capacity() )
144  
            detail::throw_invalid_argument();
144  
            detail::throw_invalid_argument();
145  

145  

146  
        out_size_ = n;
146  
        out_size_ = n;
147  
        return mutable_buffers_type(
147  
        return mutable_buffers_type(
148  
            data_ + in_pos_ + in_size_, n);
148  
            data_ + in_pos_ + in_size_, n);
149  
    }
149  
    }
150  

150  

151  
    /** Move bytes from the output to the input sequence.
151  
    /** Move bytes from the output to the input sequence.
152  

152  

153  
        Invalidates buffer sequences previously obtained
153  
        Invalidates buffer sequences previously obtained
154  
        from @ref prepare. Buffer sequences from @ref data
154  
        from @ref prepare. Buffer sequences from @ref data
155  
        remain valid.
155  
        remain valid.
156  

156  

157  
        @param n The number of bytes to commit. If greater
157  
        @param n The number of bytes to commit. If greater
158  
            than the prepared size, all prepared bytes
158  
            than the prepared size, all prepared bytes
159  
            are committed.
159  
            are committed.
160  
    */
160  
    */
161  
    void
161  
    void
162  
    commit(
162  
    commit(
163  
        std::size_t n) noexcept
163  
        std::size_t n) noexcept
164  
    {
164  
    {
165  
        if(n < out_size_)
165  
        if(n < out_size_)
166  
            in_size_ += n;
166  
            in_size_ += n;
167  
        else
167  
        else
168  
            in_size_ += out_size_;
168  
            in_size_ += out_size_;
169  
        out_size_ = 0;
169  
        out_size_ = 0;
170  
    }
170  
    }
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  
    void
181  
    void
182  
    consume(
182  
    consume(
183  
        std::size_t n) noexcept
183  
        std::size_t n) noexcept
184  
    {
184  
    {
185  
        if(n < in_size_)
185  
        if(n < in_size_)
186  
        {
186  
        {
187  
            in_pos_ += n;
187  
            in_pos_ += n;
188  
            in_size_ -= n;
188  
            in_size_ -= n;
189  
        }
189  
        }
190  
        else
190  
        else
191  
        {
191  
        {
192  
            in_pos_ = 0;
192  
            in_pos_ = 0;
193  
            in_size_ = 0;
193  
            in_size_ = 0;
194  
        }
194  
        }
195  
    }
195  
    }
196  
};
196  
};
197  

197  

198  
} // capy
198  
} // capy
199  
} // boost
199  
} // boost
200  

200  

201  
#endif
201  
#endif