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 <cstring> 28 : : #include <limits> 29 : : #include <string> 30 : : #include <string_view> 31 : : 32 : : namespace vlink { 33 : : 34 : : // FastStream 35 : 128 : FastStream::FastStream() noexcept : std::ostream(nullptr), buf_(kDefaultCapacity) { rdbuf(&buf_); } 36 : : 37 : 127 : FastStream::~FastStream() noexcept = default; 38 : : 39 : 532 : void FastStream::reset() noexcept { 40 : 532 : clear(); 41 : 532 : buf_.reset(); 42 : 532 : } 43 : : 44 : 4 : void FastStream::append_to(std::string& target) const noexcept { buf_.append_to(target); } 45 : : 46 : 548 : std::string_view FastStream::take_view() { return buf_.take_view(); } 47 : : 48 : 14 : size_t FastStream::size() const noexcept { return buf_.size(); } 49 : : 50 : 5 : size_t FastStream::capacity() const noexcept { return buf_.capacity(); } 51 : : 52 : 1 : void FastStream::shrink_to_fit() noexcept { buf_.shrink_to_fit(); } 53 : : 54 : 165 : FastStream& FastStream::write_raw(const char* data, size_t len) { 55 : 165 : buf_.xsputn(data, static_cast<std::streamsize>(len)); 56 : 165 : return *this; 57 : : } 58 : : 59 : : // FastStream::StringBuf 60 : 128 : FastStream::StringBuf::StringBuf(size_t initial_capacity) { 61 : 128 : auto actual_capacity = std::max(initial_capacity, kMinCapacity); 62 [ + - ]: 128 : buffer_.resize(actual_capacity); 63 : 128 : reset(); 64 : 128 : } 65 : : 66 : 660 : void FastStream::StringBuf::reset() noexcept { setp(buffer_.data(), buffer_.data() + buffer_.size()); } 67 : : 68 : 1 : void FastStream::StringBuf::shrink_to_fit() noexcept { 69 : 1 : buffer_.shrink_to_fit(); 70 : 1 : setp(buffer_.data(), buffer_.data() + buffer_.size()); 71 : 1 : } 72 : : 73 : 4 : void FastStream::StringBuf::append_to(std::string& target) const noexcept { 74 : 4 : target.reserve(target.size() + size()); 75 : 4 : target.append(pbase(), size()); 76 : 4 : } 77 : : 78 : 548 : std::string_view FastStream::StringBuf::take_view() { 79 : 548 : auto current_size = static_cast<size_t>(pptr() - pbase()); 80 : : 81 [ - + ]: 548 : if VUNLIKELY (current_size >= buffer_.size()) { 82 : 0 : grow_buffer(current_size + 1); 83 : : } 84 : : 85 : 548 : buffer_[current_size] = '\0'; 86 : : 87 : 548 : return {pbase(), current_size}; 88 : : } 89 : : 90 : 22 : size_t FastStream::StringBuf::size() const noexcept { return static_cast<size_t>(pptr() - pbase()); } 91 : : 92 : 5 : size_t FastStream::StringBuf::capacity() const noexcept { return buffer_.size(); } 93 : : 94 : 10 : void FastStream::StringBuf::grow_buffer(size_t required_size) { 95 : 10 : auto pos = static_cast<size_t>(pptr() - pbase()); 96 : 10 : auto new_size = buffer_.size(); 97 : : 98 [ + + ]: 10 : if VUNLIKELY (new_size > kMaxExpandSize) { 99 : 1 : new_size = required_size + kMaxExpandSize; 100 : : } else { 101 [ + + ]: 28 : while (new_size < required_size) { 102 : 19 : new_size *= 2; 103 : : } 104 : : } 105 : : 106 : 10 : buffer_.resize(new_size); 107 : 10 : setp(buffer_.data(), buffer_.data() + buffer_.size()); 108 : 10 : advance_pptr(pos); 109 : 10 : } 110 : : 111 : 3229 : void FastStream::StringBuf::advance_pptr(size_t count) noexcept { 112 : 3229 : constexpr auto kMaxBump = static_cast<size_t>(std::numeric_limits<int>::max()); 113 : : 114 [ - + ]: 3229 : while (count > kMaxBump) { 115 : : pbump(std::numeric_limits<int>::max()); // LCOV_EXCL_LINE GCOVR_EXCL_LINE 116 : : count -= kMaxBump; // LCOV_EXCL_LINE GCOVR_EXCL_LINE 117 : : } 118 : : 119 : 3229 : pbump(static_cast<int>(count)); 120 : 3229 : } 121 : : 122 : 6 : std::ostream::int_type FastStream::StringBuf::overflow(int_type ch) { 123 [ - + ]: 6 : if VUNLIKELY (traits_type::eq_int_type(ch, traits_type::eof())) { 124 : 0 : return traits_type::eof(); 125 : : } 126 : : 127 : 6 : grow_buffer(buffer_.size() + 1); 128 : : 129 : 6 : *pptr() = traits_type::to_char_type(ch); 130 : 6 : pbump(1); 131 : : 132 : 6 : return traits_type::not_eof(ch); 133 : : } 134 : : 135 : 3248 : std::streamsize FastStream::StringBuf::xsputn(const char* s, std::streamsize n) { 136 [ + + ]: 3248 : if VUNLIKELY (n <= 0) { 137 : 29 : return 0; 138 : : } 139 : : 140 : 3219 : auto count = static_cast<size_t>(n); 141 : 3219 : auto available = static_cast<size_t>(epptr() - pptr()); 142 : : 143 [ + + ]: 3219 : if VLIKELY (count <= available) { 144 : 3215 : std::memcpy(pptr(), s, count); 145 : 3215 : advance_pptr(count); 146 : 3215 : return n; 147 : : } 148 : : 149 : 4 : auto pos = static_cast<size_t>(pptr() - pbase()); 150 : 4 : auto required = pos + count; 151 : : 152 : 4 : grow_buffer(required); 153 : : 154 : 4 : std::memcpy(pptr(), s, count); 155 : 4 : advance_pptr(count); 156 : : 157 : 4 : return n; 158 : : } 159 : : 160 : : } // namespace vlink