Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_CORE_MEMORY_SPMEMSTRINGSTREAM_H_
25 : #define STAPPLER_CORE_MEMORY_SPMEMSTRINGSTREAM_H_
26 :
27 : #include "SPMemString.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::memory {
30 :
31 : constexpr size_t basic_ostringbuf_bufsize = 256;
32 :
33 : template<typename CharType>
34 : class basic_ostringbuf final : public std::basic_streambuf<CharType, std::char_traits<CharType>>, public AllocPool {
35 : public:
36 : using storage_type = storage_mem<CharType>;
37 : using allocator_type = Allocator<CharType>;
38 : using storage_allocator_type = Allocator<storage_mem<CharType>>;
39 : using traits_type = std::char_traits<CharType>;
40 : using size_type = size_t;
41 : using string_type = basic_string<CharType>;
42 : using mem_type = storage_mem<CharType, 1>;
43 : using char_type = CharType;
44 : using int_type = typename traits_type::int_type;
45 : using streambuf_type = std::basic_streambuf<CharType, std::char_traits<CharType>>;
46 :
47 53325 : basic_ostringbuf(size_type block = mem_type::get_soo_size(), const allocator_type &alloc = allocator_type()) noexcept
48 53325 : : _buf(alloc) {
49 53324 : _buf.resize(block, 0);
50 :
51 53325 : char *base = &_buf.front();
52 53324 : streambuf_type::setp(base, base + _buf.size() - 1); // -1 to make overflow() easier
53 53324 : }
54 : basic_ostringbuf(CharType *ptr, size_type block, const allocator_type &alloc = allocator_type()) noexcept
55 : : _buf(alloc) {
56 : _buf.assign_weak(ptr, block);
57 :
58 : char *base = &_buf.front();
59 : streambuf_type::setp(base, base + _buf.size() - 1); // -1 to make overflow() easier
60 : }
61 : basic_ostringbuf(basic_ostringbuf &&other, const allocator_type &alloc = allocator_type()) noexcept
62 : : _buf(std::move(other._buf), alloc) {
63 : char *base = &_buf.front();
64 : auto diff = (_buf.size() - 1) - (other.epptr() - other.pptr());
65 : streambuf_type::setp(base + diff, base + _buf.size() - 1);
66 : }
67 :
68 0 : basic_ostringbuf &operator=(basic_ostringbuf &&other) noexcept {
69 0 : _buf = move(other._buf);
70 0 : char *base = &_buf.front();
71 0 : auto diff = (_buf.size() - 1) - (other.epptr() - other.pptr());
72 0 : streambuf_type::setp(base + diff, base + _buf.size() - 1);
73 0 : return *this;
74 : }
75 :
76 52124 : virtual ~basic_ostringbuf() noexcept { }
77 :
78 64500 : bool empty() const noexcept {
79 64500 : return streambuf_type::pptr() == _buf.data();
80 : }
81 :
82 100848 : size_type size() const noexcept {
83 100848 : return (streambuf_type::pptr() - _buf.data());
84 : }
85 :
86 : CharType *data() noexcept {
87 : return _buf.data();
88 : }
89 :
90 48523 : const CharType *data() const noexcept {
91 48523 : return _buf.data();
92 : }
93 :
94 52100 : string_type str() const noexcept {
95 52100 : string_type ret;
96 52100 : ret.assign(_buf.data(), size());
97 52100 : return ret;
98 : }
99 :
100 46024 : void clear() {
101 46024 : char *base = &_buf.front();
102 46024 : streambuf_type::setp(base, base + _buf.size() - 1); // -1 to make overflow() easier
103 46025 : memset(_buf.data(), 0, _buf.size());
104 46025 : }
105 :
106 375 : void reserve(size_t size) {
107 375 : auto psize = (streambuf_type::pptr() - _buf.data());
108 375 : _buf.reserve(size + 1);
109 375 : _buf.resize(size + 1, 0);
110 :
111 375 : char *base = &_buf.front();
112 375 : streambuf_type::setp(base + psize, base + _buf.size() - 1); // -1 to make overflow() easier
113 375 : }
114 :
115 : basic_ostringbuf(const basic_ostringbuf &) = delete;
116 : basic_ostringbuf & operator = (const basic_ostringbuf &) = delete;
117 :
118 : const allocator_type &get_allocator() const noexcept { return _buf.get_allocator(); }
119 :
120 : protected:
121 34225 : void make_flush() {
122 34225 : auto diff = streambuf_type::pptr() - &_buf.front();
123 34223 : _buf.resize(std::max(size_type(diff * 2), basic_ostringbuf_bufsize));
124 34225 : char *base = &_buf.front();
125 34225 : streambuf_type::setp(base + diff, base + _buf.size() - 1); // -1 to make overflow() easier
126 34224 : }
127 :
128 34225 : virtual int_type overflow(int_type ch) override {
129 34225 : if (ch != traits_type::eof()) {
130 34225 : *streambuf_type::pptr() = ch;
131 34225 : streambuf_type::pbump(1);
132 34225 : make_flush();
133 34224 : return ch;
134 : }
135 :
136 0 : return traits_type::eof();
137 : }
138 0 : virtual int sync() override {
139 0 : make_flush();
140 0 : return 0;
141 : }
142 :
143 : mem_type _buf;
144 : };
145 :
146 :
147 : template <typename CharType>
148 : class basic_ostringstream final : public std::basic_ostream<CharType>, public AllocPool {
149 : public:
150 : // Types:
151 : using char_type = CharType;
152 : using traits_type = std::char_traits<CharType>;
153 :
154 : using allocator_type = Allocator<CharType>;
155 : using int_type = typename traits_type::int_type;
156 : using pos_type = typename traits_type::pos_type;
157 : using off_type = typename traits_type::off_type;
158 : using size_type = size_t;
159 :
160 : // Non-standard types:
161 : using string_type = basic_string<CharType>;
162 : using stringbuf_type = basic_ostringbuf<CharType>;
163 : using ostream_type = std::basic_ostream<char_type>;
164 :
165 : private:
166 : stringbuf_type _buf;
167 :
168 : public:
169 : explicit
170 53325 : basic_ostringstream(size_type block = stringbuf_type::mem_type::get_soo_size(), const allocator_type &alloc = allocator_type()) noexcept
171 53325 : : ostream_type(&_buf), _buf(block, alloc) {
172 53324 : this->init(&_buf);
173 53324 : }
174 :
175 : basic_ostringstream(CharType *ptr, size_type block, const allocator_type &alloc = allocator_type()) noexcept
176 : : ostream_type(&_buf), _buf(ptr, block, alloc) {
177 : this->init(&_buf);
178 : }
179 :
180 : basic_ostringstream(basic_ostringstream && rhs) noexcept
181 : : ostream_type(std::move(rhs)), _buf(std::move(rhs._buf)) {
182 : ostream_type::set_rdbuf(&_buf);
183 : }
184 :
185 0 : basic_ostringstream & operator=(basic_ostringstream && rhs) noexcept {
186 0 : ostream_type::operator=(std::move(rhs));
187 0 : _buf = std::move(rhs._buf);
188 0 : return *this;
189 : }
190 :
191 52124 : ~basic_ostringstream() noexcept {}
192 :
193 : basic_ostringstream(const basic_ostringstream &) = delete;
194 : basic_ostringstream & operator=(const basic_ostringstream &) = delete;
195 :
196 : void swap(basic_ostringstream & rhs) {
197 : ostream_type::swap(rhs);
198 : _buf.swap(rhs._buf);
199 : }
200 :
201 : stringbuf_type * rdbuf() const {
202 : return const_cast<stringbuf_type *>(&_buf);
203 : }
204 :
205 52100 : string_type str() const noexcept { return _buf.str(); }
206 48525 : string_type weak() const noexcept { return string_type::make_weak(data(), size()); }
207 46025 : void clear() { _buf.clear(); }
208 :
209 64499 : bool empty() const noexcept { return _buf.empty(); }
210 48748 : size_t size() const noexcept { return _buf.size(); }
211 : CharType *data() noexcept { return _buf.data(); }
212 48523 : const CharType *data() const noexcept { return _buf.data(); }
213 :
214 375 : void reserve(size_t size) { _buf.reserve(size); }
215 :
216 : const allocator_type &get_allocator() const noexcept { return _buf.get_allocator(); }
217 : };
218 :
219 : using ostringstream = basic_ostringstream<char>;
220 :
221 : template<typename CharType> inline std::basic_ostream<CharType> &
222 100 : operator << (std::basic_ostream<CharType> & os, const basic_ostringstream<CharType> & str) {
223 100 : return os << str.str();
224 : }
225 :
226 : }
227 :
228 : #endif /* STAPPLER_CORE_MEMORY_SPMEMSTRINGSTREAM_H_ */
|