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_STRING_DYNAMIC_BUFFER_HPP
10  
#ifndef BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_STRING_DYNAMIC_BUFFER_HPP
11  
#define BOOST_CAPY_BUFFERS_STRING_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  
#include <string>
16  
#include <string>
17  

17  

18  
namespace boost {
18  
namespace boost {
19  
namespace capy {
19  
namespace capy {
20  

20  

21  
/** A dynamic buffer using an underlying string
21  
/** A dynamic buffer using an underlying string
22  
*/
22  
*/
23  
template<
23  
template<
24  
    class CharT,
24  
    class CharT,
25  
    class Traits = std::char_traits<CharT>,
25  
    class Traits = std::char_traits<CharT>,
26  
    class Allocator = std::allocator<CharT>>
26  
    class Allocator = std::allocator<CharT>>
27  
class basic_string_dynamic_buffer
27  
class basic_string_dynamic_buffer
28  
{
28  
{
29  
    std::basic_string<
29  
    std::basic_string<
30  
        CharT, Traits, Allocator>* s_;
30  
        CharT, Traits, Allocator>* s_;
31  
    std::size_t max_size_;
31  
    std::size_t max_size_;
32  

32  

33  
    std::size_t in_size_ = 0;
33  
    std::size_t in_size_ = 0;
34  
    std::size_t out_size_ = 0;
34  
    std::size_t out_size_ = 0;
35  

35  

36  
public:
36  
public:
37  
    using is_dynamic_buffer_adapter = void;
37  
    using is_dynamic_buffer_adapter = void;
38  
    using string_type = std::basic_string<
38  
    using string_type = std::basic_string<
39  
        CharT, Traits, Allocator>;
39  
        CharT, Traits, Allocator>;
40  
    using const_buffers_type = const_buffer;
40  
    using const_buffers_type = const_buffer;
41  
    using mutable_buffers_type = mutable_buffer;
41  
    using mutable_buffers_type = mutable_buffer;
42  

42  

43  
    ~basic_string_dynamic_buffer() = default;
43  
    ~basic_string_dynamic_buffer() = default;
44  

44  

45  
    /** Constructor.
45  
    /** Constructor.
46  
    */
46  
    */
47  
    basic_string_dynamic_buffer(
47  
    basic_string_dynamic_buffer(
48  
        basic_string_dynamic_buffer&& other) noexcept
48  
        basic_string_dynamic_buffer&& other) noexcept
49  
        : s_(other.s_)
49  
        : s_(other.s_)
50  
        , max_size_(other.max_size_)
50  
        , max_size_(other.max_size_)
51  
        , in_size_(other.in_size_)
51  
        , in_size_(other.in_size_)
52  
        , out_size_(other.out_size_)
52  
        , out_size_(other.out_size_)
53  
    {
53  
    {
54  
        other.s_ = nullptr;
54  
        other.s_ = nullptr;
55  
    }
55  
    }
56  

56  

57  
    /** Constructor.
57  
    /** Constructor.
58  
    */
58  
    */
59  
    explicit
59  
    explicit
60  
    basic_string_dynamic_buffer(
60  
    basic_string_dynamic_buffer(
61  
        string_type* s,
61  
        string_type* s,
62  
        std::size_t max_size =
62  
        std::size_t max_size =
63  
            std::size_t(-1)) noexcept
63  
            std::size_t(-1)) noexcept
64  
        : s_(s)
64  
        : s_(s)
65  
        , max_size_(
65  
        , max_size_(
66  
            max_size > s_->max_size()
66  
            max_size > s_->max_size()
67  
                ? s_->max_size()
67  
                ? s_->max_size()
68  
                : max_size)
68  
                : max_size)
69  
    {
69  
    {
70  
        if(s_->size() > max_size_)
70  
        if(s_->size() > max_size_)
71  
            s_->resize(max_size_);
71  
            s_->resize(max_size_);
72  
        in_size_ = s_->size();
72  
        in_size_ = s_->size();
73  
    }
73  
    }
74  

74  

75  
    /** Assignment.
75  
    /** Assignment.
76  
    */
76  
    */
77  
    basic_string_dynamic_buffer& operator=(
77  
    basic_string_dynamic_buffer& operator=(
78  
        basic_string_dynamic_buffer const&) = delete;
78  
        basic_string_dynamic_buffer const&) = delete;
79  

79  

80  
    std::size_t
80  
    std::size_t
81  
    size() const noexcept
81  
    size() const noexcept
82  
    {
82  
    {
83  
        return in_size_;
83  
        return in_size_;
84  
    }
84  
    }
85  

85  

86  
    std::size_t
86  
    std::size_t
87  
    max_size() const noexcept
87  
    max_size() const noexcept
88  
    {
88  
    {
89  
        return max_size_;
89  
        return max_size_;
90  
    }
90  
    }
91  

91  

92  
    std::size_t
92  
    std::size_t
93  
    capacity() const noexcept
93  
    capacity() const noexcept
94  
    {
94  
    {
95  
        if(s_->capacity() <= max_size_)
95  
        if(s_->capacity() <= max_size_)
96  
            return s_->capacity() - in_size_;
96  
            return s_->capacity() - in_size_;
97  
        return max_size_ - in_size_;
97  
        return max_size_ - in_size_;
98  
    }
98  
    }
99  

99  

100  
    const_buffers_type
100  
    const_buffers_type
101  
    data() const noexcept
101  
    data() const noexcept
102  
    {
102  
    {
103  
        return const_buffers_type(
103  
        return const_buffers_type(
104  
            s_->data(), in_size_);
104  
            s_->data(), in_size_);
105  
    }
105  
    }
106  

106  

107  
    mutable_buffers_type
107  
    mutable_buffers_type
108  
    prepare(std::size_t n)
108  
    prepare(std::size_t n)
109  
    {
109  
    {
110  
        // n exceeds available space
110  
        // n exceeds available space
111  
        if(n > max_size_ - in_size_)
111  
        if(n > max_size_ - in_size_)
112  
            detail::throw_invalid_argument();
112  
            detail::throw_invalid_argument();
113  

113  

114  
        if( s_->size() < in_size_ + n)
114  
        if( s_->size() < in_size_ + n)
115  
            s_->resize(in_size_ + n);
115  
            s_->resize(in_size_ + n);
116  
        out_size_ = n;
116  
        out_size_ = n;
117  
        return mutable_buffers_type(
117  
        return mutable_buffers_type(
118  
            &(*s_)[in_size_], out_size_);
118  
            &(*s_)[in_size_], out_size_);
119  
    }
119  
    }
120  

120  

121  
    void commit(std::size_t n) noexcept
121  
    void commit(std::size_t n) noexcept
122  
    {
122  
    {
123  
        if(n < out_size_)
123  
        if(n < out_size_)
124  
            in_size_ += n;
124  
            in_size_ += n;
125  
        else
125  
        else
126  
            in_size_ += out_size_;
126  
            in_size_ += out_size_;
127  
        out_size_ = 0;
127  
        out_size_ = 0;
128  
        s_->resize(in_size_);
128  
        s_->resize(in_size_);
129  
    }
129  
    }
130  

130  

131  
    void consume(std::size_t n) noexcept
131  
    void consume(std::size_t n) noexcept
132  
    {
132  
    {
133  
        if(n < in_size_)
133  
        if(n < in_size_)
134  
        {
134  
        {
135  
            s_->erase(0, n);
135  
            s_->erase(0, n);
136  
            in_size_ -= n;
136  
            in_size_ -= n;
137  
        }
137  
        }
138  
        else
138  
        else
139  
        {
139  
        {
140  
            s_->clear();
140  
            s_->clear();
141  
            in_size_ = 0;
141  
            in_size_ = 0;
142  
        }
142  
        }
143  
        out_size_ = 0;
143  
        out_size_ = 0;
144  
    }
144  
    }
145  
};
145  
};
146  

146  

147  
using string_dynamic_buffer = basic_string_dynamic_buffer<char>;
147  
using string_dynamic_buffer = basic_string_dynamic_buffer<char>;
148  

148  

149  
/** Create a dynamic buffer from a string.
149  
/** Create a dynamic buffer from a string.
150  

150  

151  
    @param s The string to wrap.
151  
    @param s The string to wrap.
152  
    @param max_size Optional maximum size limit.
152  
    @param max_size Optional maximum size limit.
153  
    @return A string_dynamic_buffer wrapping the string.
153  
    @return A string_dynamic_buffer wrapping the string.
154  
*/
154  
*/
155  
template<class CharT, class Traits, class Allocator>
155  
template<class CharT, class Traits, class Allocator>
156  
basic_string_dynamic_buffer<CharT, Traits, Allocator>
156  
basic_string_dynamic_buffer<CharT, Traits, Allocator>
157  
dynamic_buffer(
157  
dynamic_buffer(
158  
    std::basic_string<CharT, Traits, Allocator>& s,
158  
    std::basic_string<CharT, Traits, Allocator>& s,
159  
    std::size_t max_size = std::size_t(-1))
159  
    std::size_t max_size = std::size_t(-1))
160  
{
160  
{
161  
    return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size);
161  
    return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size);
162  
}
162  
}
163  

163  

164  
} // capy
164  
} // capy
165  
} // boost
165  
} // boost
166  

166  

167  
#endif
167  
#endif