Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./base/fast_stream.h"
25 : :
26 : : #include <algorithm>
27 : : #include <charconv>
28 : : #include <cstring>
29 : : #include <limits>
30 : : #include <locale>
31 : : #include <string>
32 : : #include <string_view>
33 : :
34 : : #include "./base/helpers.h"
35 : :
36 : : namespace vlink {
37 : :
38 : : // FastStream
39 : 174 : FastStream::FastStream() noexcept : std::ostream(nullptr), buf_(kDefaultCapacity) { rdbuf(&buf_); }
40 : :
41 : 173 : FastStream::~FastStream() noexcept = default;
42 : :
43 : 4875 : void FastStream::reset() noexcept {
44 : 4875 : clear();
45 : 4875 : buf_.reset();
46 : 4875 : }
47 : :
48 : 4 : void FastStream::append_to(std::string& target) const { buf_.append_to(target); }
49 : :
50 : 4894 : std::string_view FastStream::take_view() { return buf_.take_view(); }
51 : :
52 : 15 : size_t FastStream::size() const noexcept { return buf_.size(); }
53 : :
54 : 5 : size_t FastStream::capacity() const noexcept { return buf_.capacity(); }
55 : :
56 : 2 : void FastStream::shrink_to_fit() noexcept { buf_.shrink_to_fit(); }
57 : :
58 : 12809 : FastStream& FastStream::write_raw(const char* data, size_t len) {
59 : 12809 : buf_.xsputn(data, static_cast<std::streamsize>(len));
60 : 12809 : return *this;
61 : : }
62 : :
63 : 0 : FastStream& FastStream::push_floating(float value) {
64 [ # # # # : 0 : if VLIKELY (width() == 0 && precision() == 6 && flags() == (std::ios_base::dec | std::ios_base::skipws) &&
# # # # #
# # # # #
# # # # #
# ]
65 : : getloc() == std::locale::classic()) {
66 : : char buffer[32];
67 : 0 : auto size = Helpers::format_floating_to(buffer, sizeof(buffer), value);
68 : :
69 [ # # ]: 0 : return write_raw(buffer, size);
70 : : }
71 : :
72 : 0 : static_cast<std::ostream&>(*this) << value;
73 : :
74 : 0 : return *this;
75 : : }
76 : :
77 : 1 : FastStream& FastStream::push_floating(double value) {
78 [ + - - + : 1 : if VLIKELY (width() == 0 && precision() == 6 && flags() == (std::ios_base::dec | std::ios_base::skipws) &&
- + - - -
+ - - - -
- + - + -
- ]
79 : : getloc() == std::locale::classic()) {
80 : : char buffer[32];
81 : 0 : auto size = Helpers::format_floating_to(buffer, sizeof(buffer), value);
82 : :
83 [ # # ]: 0 : return write_raw(buffer, size);
84 : : }
85 : :
86 : 1 : static_cast<std::ostream&>(*this) << value;
87 : :
88 : 1 : return *this;
89 : : }
90 : :
91 : 4815 : bool FastStream::push_integer(int64_t value) {
92 [ + + + + : 4815 : if VUNLIKELY (width() != 0 || flags() != (std::ios_base::dec | std::ios_base::skipws)) {
+ + ]
93 : 8 : return false;
94 : : }
95 : :
96 : : static constexpr size_t kBufferSize{std::numeric_limits<int64_t>::digits10 + 3};
97 : :
98 : : char buffer[kBufferSize];
99 [ + - ]: 4807 : auto result = std::to_chars(buffer, buffer + sizeof(buffer), value);
100 : :
101 [ - + ]: 4807 : if VUNLIKELY (result.ec != std::errc{}) {
102 : 0 : return false;
103 : : }
104 : :
105 [ + - ]: 4807 : write_raw(buffer, static_cast<size_t>(result.ptr - buffer));
106 : :
107 : 4807 : return true;
108 : : }
109 : :
110 : 133 : bool FastStream::push_integer(uint64_t value) {
111 [ + - - + : 133 : if VUNLIKELY (width() != 0 || flags() != (std::ios_base::dec | std::ios_base::skipws)) {
- + ]
112 : 0 : return false;
113 : : }
114 : :
115 : : static constexpr size_t kBufferSize{std::numeric_limits<uint64_t>::digits10 + 3};
116 : :
117 : : char buffer[kBufferSize];
118 [ + - ]: 133 : auto result = std::to_chars(buffer, buffer + sizeof(buffer), value);
119 : :
120 [ - + ]: 133 : if VUNLIKELY (result.ec != std::errc{}) {
121 : 0 : return false;
122 : : }
123 : :
124 [ + - ]: 133 : write_raw(buffer, static_cast<size_t>(result.ptr - buffer));
125 : :
126 : 133 : return true;
127 : : }
128 : :
129 : : // FastStream::StringBuf
130 : 174 : FastStream::StringBuf::StringBuf(size_t initial_capacity) {
131 : 174 : auto actual_capacity = std::max(initial_capacity, kMinCapacity);
132 [ + - ]: 174 : buffer_.resize(actual_capacity);
133 : 174 : reset();
134 : 174 : }
135 : :
136 : 5049 : void FastStream::StringBuf::reset() noexcept { setp(buffer_.data(), buffer_.data() + buffer_.size()); }
137 : :
138 : 2 : void FastStream::StringBuf::shrink_to_fit() noexcept {
139 : 2 : const auto current_size = static_cast<size_t>(pptr() - pbase());
140 : :
141 : 2 : buffer_.shrink_to_fit();
142 : 2 : setp(buffer_.data(), buffer_.data() + buffer_.size());
143 : 2 : advance_pptr(current_size);
144 : 2 : }
145 : :
146 : 4 : void FastStream::StringBuf::append_to(std::string& target) const {
147 : 4 : target.reserve(target.size() + size());
148 : 4 : target.append(pbase(), size());
149 : 4 : }
150 : :
151 : 4894 : std::string_view FastStream::StringBuf::take_view() {
152 : 4894 : auto current_size = static_cast<size_t>(pptr() - pbase());
153 : :
154 [ - + ]: 4894 : if VUNLIKELY (current_size >= buffer_.size()) {
155 : 0 : grow_buffer(current_size + 1);
156 : : }
157 : :
158 : 4894 : buffer_[current_size] = '\0';
159 : :
160 : 4894 : return {pbase(), current_size};
161 : : }
162 : :
163 : 23 : size_t FastStream::StringBuf::size() const noexcept { return static_cast<size_t>(pptr() - pbase()); }
164 : :
165 : 5 : size_t FastStream::StringBuf::capacity() const noexcept { return buffer_.size(); }
166 : :
167 : 6 : std::ostream::int_type FastStream::StringBuf::overflow(int_type ch) {
168 [ - + ]: 6 : if VUNLIKELY (traits_type::eq_int_type(ch, traits_type::eof())) {
169 : 0 : return traits_type::eof();
170 : : }
171 : :
172 : 6 : grow_buffer(buffer_.size() + 1);
173 : :
174 : 6 : *pptr() = traits_type::to_char_type(ch);
175 : 6 : pbump(1);
176 : :
177 : 6 : return traits_type::not_eof(ch);
178 : : }
179 : :
180 : 12871 : std::streamsize FastStream::StringBuf::xsputn(const char* s, std::streamsize n) {
181 [ + + ]: 12871 : if VUNLIKELY (n <= 0) {
182 : 26 : return 0;
183 : : }
184 : :
185 : 12845 : auto count = static_cast<size_t>(n);
186 : 12845 : auto available = static_cast<size_t>(epptr() - pptr());
187 : :
188 [ + + ]: 12845 : if VLIKELY (count <= available) {
189 : 12840 : std::memcpy(pptr(), s, count);
190 : 12840 : advance_pptr(count);
191 : 12840 : return n;
192 : : }
193 : :
194 : 5 : auto pos = static_cast<size_t>(pptr() - pbase());
195 : 5 : auto required = pos + count;
196 : :
197 : 5 : grow_buffer(required);
198 : :
199 : 5 : std::memcpy(pptr(), s, count);
200 : 5 : advance_pptr(count);
201 : :
202 : 5 : return n;
203 : : }
204 : :
205 : 11 : void FastStream::StringBuf::grow_buffer(size_t required_size) {
206 : 11 : auto pos = static_cast<size_t>(pptr() - pbase());
207 : 11 : auto new_size = buffer_.size();
208 : :
209 [ + + ]: 11 : if VUNLIKELY (new_size > kMaxExpandSize) {
210 : 1 : new_size = required_size + kMaxExpandSize;
211 : : } else {
212 [ + + ]: 30 : while (new_size < required_size) {
213 : 20 : new_size *= 2;
214 : : }
215 : : }
216 : :
217 : 11 : buffer_.resize(new_size);
218 : 11 : setp(buffer_.data(), buffer_.data() + buffer_.size());
219 : 11 : advance_pptr(pos);
220 : 11 : }
221 : :
222 : 12858 : void FastStream::StringBuf::advance_pptr(size_t count) noexcept {
223 : : static constexpr auto kMaxBump = static_cast<size_t>(std::numeric_limits<int>::max());
224 : :
225 [ - + ]: 12858 : while (count > kMaxBump) {
226 : : pbump(std::numeric_limits<int>::max()); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
227 : : count -= kMaxBump; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
228 : : }
229 : :
230 : 12858 : pbump(static_cast<int>(count));
231 : 12858 : }
232 : :
233 : : } // namespace vlink
|