Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "textstream.h"
23 :
24 : #include <array>
25 : #include <charconv>
26 :
27 : #include "global/io/iodevice.h"
28 : #include "global/types/bytearray.h"
29 : #include "global/types/string.h"
30 :
31 : #include "global/log.h"
32 :
33 : using namespace muse;
34 :
35 : static constexpr int TEXTSTREAM_BUFFERSIZE = 16384;
36 :
37 6 : TextStream::TextStream(io::IODevice* device)
38 6 : : m_device(device)
39 : {
40 6 : m_buf.reserve(TEXTSTREAM_BUFFERSIZE);
41 6 : }
42 :
43 2247 : TextStream::~TextStream()
44 : {
45 2247 : flush();
46 2247 : }
47 :
48 2241 : void TextStream::setDevice(io::IODevice* device)
49 : {
50 2241 : m_device = device;
51 2241 : }
52 :
53 7328 : void TextStream::flush()
54 : {
55 7328 : if (m_device && m_device->isOpen()) {
56 6108 : m_device->write(m_buf.data(), m_buf.size());
57 6108 : m_buf.clear();
58 : }
59 7328 : }
60 :
61 9842536 : TextStream& TextStream::operator<<(char ch)
62 : {
63 9842536 : write(&ch, 1);
64 9842536 : return *this;
65 : }
66 :
67 154669 : TextStream& TextStream::operator<<(const int32_t val)
68 : {
69 : // ceil(log_10(2^31)) = 10 (+ sign)
70 154669 : std::array<char, 11> buf{};
71 464007 : const auto [last, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), val);
72 154669 : IF_ASSERT_FAILED(ec == std::errc {}) {
73 0 : return *this;
74 : }
75 :
76 464007 : write(buf.data(), static_cast<size_t>(last - buf.data()));
77 :
78 154669 : return *this;
79 : }
80 :
81 0 : TextStream& TextStream::operator<<(const uint32_t val)
82 : {
83 : // ceil(log_10(2^32)) = 10
84 0 : std::array<char, 10> buf{};
85 0 : const auto [last, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), val);
86 0 : IF_ASSERT_FAILED(ec == std::errc {}) {
87 0 : return *this;
88 : }
89 :
90 0 : write(buf.data(), static_cast<size_t>(last - buf.data()));
91 0 : return *this;
92 : }
93 :
94 13085 : TextStream& TextStream::operator<<(double val)
95 : {
96 : // macOS: requires macOS 13.3 at runtime
97 : // linux: requires at least libstdc++ 11 (we compile with libstdc++ 10) or libc++ 14
98 : #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130300) \
99 : || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 160300) \
100 : || defined(_MSC_VER) \
101 : || (!defined(__APPLE__) && defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 14000) \
102 : || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 11)
103 13085 : std::array<char, 24> buf{};
104 :
105 : // emulate std::stringstream default behavior
106 13085 : constexpr auto format = std::chars_format::general;
107 13085 : constexpr int precision = 6;
108 39255 : const auto [last, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), val, format, precision);
109 13085 : IF_ASSERT_FAILED(ec == std::errc {}) {
110 0 : return *this;
111 : }
112 39255 : write(buf.data(), static_cast<size_t>(last - buf.data()));
113 : #else
114 : std::stringstream ss;
115 : ss << val;
116 : std::string buf = ss.str();
117 : write(buf.data(), buf.size());
118 : #endif
119 :
120 13085 : return *this;
121 : }
122 :
123 0 : TextStream& TextStream::operator<<(const int64_t val)
124 : {
125 : // ceil(log_10(2^63)) = 20 (+ sign)
126 0 : std::array<char, 21> buf{};
127 0 : const auto [last, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), val);
128 0 : IF_ASSERT_FAILED(ec == std::errc {}) {
129 0 : return *this;
130 : }
131 :
132 0 : write(buf.data(), static_cast<size_t>(last - buf.data()));
133 :
134 0 : return *this;
135 : }
136 :
137 2800 : TextStream& TextStream::operator<<(const uint64_t val)
138 : {
139 : // ceil(log_10(2^64)) = 20
140 2800 : std::array<char, 20> buf{};
141 8400 : const auto [last, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), val);
142 2800 : IF_ASSERT_FAILED(ec == std::errc {}) {
143 0 : return *this;
144 : }
145 :
146 8400 : write(buf.data(), static_cast<size_t>(last - buf.data()));
147 :
148 2800 : return *this;
149 : }
150 :
151 569409 : TextStream& TextStream::operator<<(const char* s)
152 : {
153 569409 : return operator<<(std::string_view { s });
154 : }
155 :
156 1914334 : TextStream& TextStream::operator<<(const std::string_view str)
157 : {
158 1914334 : write(str.data(), str.size());
159 1914334 : return *this;
160 : }
161 :
162 : #ifndef NO_QT_SUPPORT
163 0 : TextStream& TextStream::operator<<(const QString& s)
164 : {
165 0 : QByteArray ba = s.toUtf8();
166 0 : write(ba.constData(), ba.length());
167 0 : return *this;
168 0 : }
169 :
170 : #endif
171 :
172 0 : TextStream& TextStream::operator<<(const ByteArray& b)
173 : {
174 0 : write(reinterpret_cast<const char*>(b.constData()), b.size());
175 0 : return *this;
176 : }
177 :
178 43133 : TextStream& TextStream::operator<<(const String& s)
179 : {
180 43133 : ByteArray b = s.toUtf8();
181 43133 : write(reinterpret_cast<const char*>(b.constData()), b.size());
182 43133 : return *this;
183 43133 : }
184 :
185 11970557 : void TextStream::write(const char* ch, size_t len)
186 : {
187 11970557 : m_buf.insert(m_buf.end(), reinterpret_cast<const uint8_t*>(ch), reinterpret_cast<const uint8_t*>(ch + len));
188 11970557 : if (m_device && m_buf.size() > TEXTSTREAM_BUFFERSIZE) {
189 596 : flush();
190 : }
191 11970557 : }
|