1 /* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
2
3 #ifndef MPT_STRING_BUFFER_HPP
4 #define MPT_STRING_BUFFER_HPP
5
6
7
8 #include "mpt/base/detect.hpp"
9 #include "mpt/base/namespace.hpp"
10 #include "mpt/detect/mfc.hpp"
11 #include "mpt/string/types.hpp"
12
13 #include <algorithm>
14 #include <array>
15 #include <string>
16 #include <string_view>
17 #include <type_traits>
18
19 #include <cassert>
20 #include <cstddef>
21
22 #if MPT_DETECTED_MFC
23 // cppcheck-suppress missingInclude
24 #include <afx.h>
25 #endif // MPT_DETECTED_MFC
26
27
28
29 namespace mpt {
30 inline namespace MPT_INLINE_NS {
31
32
33
34
35 template <typename Tstring, typename Tchar>
36 class StringBufRefImpl {
37 private:
38 Tchar * buf;
39 std::size_t size;
40
41 public:
42 // cppcheck false-positive
43 // cppcheck-suppress uninitMemberVar
StringBufRefImpl(Tchar * buf_,std::size_t size_)44 explicit StringBufRefImpl(Tchar * buf_, std::size_t size_)
45 : buf(buf_)
46 , size(size_) {
47 static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type));
48 assert(size > 0);
49 }
50 StringBufRefImpl(const StringBufRefImpl &) = delete;
51 StringBufRefImpl(StringBufRefImpl &&) = default;
52 StringBufRefImpl & operator=(const StringBufRefImpl &) = delete;
53 StringBufRefImpl & operator=(StringBufRefImpl &&) = delete;
operator Tstring() const54 operator Tstring() const {
55 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
56 return Tstring(buf, buf + len);
57 }
operator std::basic_string_view<Tchar>() const58 explicit operator std::basic_string_view<Tchar>() const {
59 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
60 return std::basic_string_view<Tchar>(buf, buf + len);
61 }
empty() const62 bool empty() const {
63 return buf[0] == Tchar('\0');
64 }
operator =(const Tstring & str)65 StringBufRefImpl & operator=(const Tstring & str) {
66 std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
67 std::fill(buf + std::min(str.length(), size - 1), buf + size, Tchar('\0'));
68 return *this;
69 }
70 };
71
72 template <typename Tstring, typename Tchar>
73 class StringBufRefImpl<Tstring, const Tchar> {
74 private:
75 const Tchar * buf;
76 std::size_t size;
77
78 public:
79 // cppcheck false-positive
80 // cppcheck-suppress uninitMemberVar
StringBufRefImpl(const Tchar * buf_,std::size_t size_)81 explicit StringBufRefImpl(const Tchar * buf_, std::size_t size_)
82 : buf(buf_)
83 , size(size_) {
84 static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type));
85 assert(size > 0);
86 }
87 StringBufRefImpl(const StringBufRefImpl &) = delete;
88 StringBufRefImpl(StringBufRefImpl &&) = default;
89 StringBufRefImpl & operator=(const StringBufRefImpl &) = delete;
90 StringBufRefImpl & operator=(StringBufRefImpl &&) = delete;
operator Tstring() const91 operator Tstring() const {
92 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
93 return Tstring(buf, buf + len);
94 }
operator std::basic_string_view<Tchar>() const95 explicit operator std::basic_string_view<Tchar>() const {
96 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
97 return std::basic_string_view<Tchar>(buf, len);
98 }
empty() const99 bool empty() const {
100 return buf[0] == Tchar('\0');
101 }
102 };
103
104
105
106 template <typename Tstring, typename Tchar, std::size_t size>
ReadTypedBuf(const std::array<Tchar,size> & buf)107 inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(const std::array<Tchar, size> & buf) {
108 return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf.data(), size);
109 }
110 template <typename Tstring, typename Tchar, std::size_t size>
ReadTypedBuf(const Tchar (& buf)[size])111 inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(const Tchar (&buf)[size]) {
112 return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
113 }
114 template <typename Tstring, typename Tchar>
ReadTypedBuf(const Tchar * buf,std::size_t size)115 inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(const Tchar * buf, std::size_t size) {
116 return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
117 }
118 template <typename Tstring, typename Tchar, std::size_t size>
WriteTypedBuf(std::array<Tchar,size> & buf)119 inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(std::array<Tchar, size> & buf) {
120 return StringBufRefImpl<Tstring, Tchar>(buf.data(), size);
121 }
122 template <typename Tstring, typename Tchar, std::size_t size>
WriteTypedBuf(Tchar (& buf)[size])123 inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar (&buf)[size]) {
124 return StringBufRefImpl<Tstring, Tchar>(buf, size);
125 }
126 template <typename Tstring, typename Tchar>
WriteTypedBuf(Tchar * buf,std::size_t size)127 inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar * buf, std::size_t size) {
128 return StringBufRefImpl<Tstring, Tchar>(buf, size);
129 }
130
131
132
133 template <typename Tchar, std::size_t size>
ReadAutoBuf(const std::array<Tchar,size> & buf)134 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(const std::array<Tchar, size> & buf) {
135 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf.data(), size);
136 }
137 template <typename Tchar, std::size_t size>
ReadAutoBuf(const Tchar (& buf)[size])138 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(const Tchar (&buf)[size]) {
139 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
140 }
141 template <typename Tchar>
ReadAutoBuf(const Tchar * buf,std::size_t size)142 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(const Tchar * buf, std::size_t size) {
143 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
144 }
145 template <typename Tchar, std::size_t size>
WriteAutoBuf(std::array<Tchar,size> & buf)146 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(std::array<Tchar, size> & buf) {
147 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf.data(), size);
148 }
149 template <typename Tchar, std::size_t size>
WriteAutoBuf(Tchar (& buf)[size])150 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar (&buf)[size]) {
151 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
152 }
153 template <typename Tchar>
WriteAutoBuf(Tchar * buf,std::size_t size)154 inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar * buf, std::size_t size) {
155 return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
156 }
157
158
159
160 #if MPT_OS_WINDOWS
161
162 template <typename Tchar, std::size_t size>
ReadWinBuf(const std::array<Tchar,size> & buf)163 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(const std::array<Tchar, size> & buf) {
164 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf.data(), size);
165 }
166 template <typename Tchar, std::size_t size>
ReadWinBuf(const Tchar (& buf)[size])167 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(const Tchar (&buf)[size]) {
168 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
169 }
170 template <typename Tchar>
ReadWinBuf(const Tchar * buf,std::size_t size)171 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(const Tchar * buf, std::size_t size) {
172 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
173 }
174 template <typename Tchar, std::size_t size>
WriteWinBuf(std::array<Tchar,size> & buf)175 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(std::array<Tchar, size> & buf) {
176 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf.data(), size);
177 }
178 template <typename Tchar, std::size_t size>
WriteWinBuf(Tchar (& buf)[size])179 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar (&buf)[size]) {
180 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
181 }
182 template <typename Tchar>
WriteWinBuf(Tchar * buf,std::size_t size)183 inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar * buf, std::size_t size) {
184 return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
185 }
186
187 #endif // MPT_OS_WINDOWS
188
189
190
191 #if MPT_DETECTED_MFC
192
193 template <typename Tchar>
194 class CStringBufRefImpl {
195 private:
196 Tchar * buf;
197 std::size_t size;
198
199 public:
200 // cppcheck false-positive
201 // cppcheck-suppress uninitMemberVar
CStringBufRefImpl(Tchar * buf_,std::size_t size_)202 explicit CStringBufRefImpl(Tchar * buf_, std::size_t size_)
203 : buf(buf_)
204 , size(size_) {
205 assert(size > 0);
206 }
207 CStringBufRefImpl(const CStringBufRefImpl &) = delete;
208 CStringBufRefImpl(CStringBufRefImpl &&) = default;
209 CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete;
210 CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete;
operator CString() const211 operator CString() const {
212 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
213 return CString(buf, mpt::saturate_cast<int>(len));
214 }
operator =(const CString & str)215 CStringBufRefImpl & operator=(const CString & str) {
216 std::copy(str.GetString(), str.GetString() + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf);
217 std::fill(buf + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf + size, Tchar('\0'));
218 return *this;
219 }
220 };
221
222 template <typename Tchar>
223 class CStringBufRefImpl<const Tchar> {
224 private:
225 const Tchar * buf;
226 std::size_t size;
227
228 public:
229 // cppcheck false-positive
230 // cppcheck-suppress uninitMemberVar
CStringBufRefImpl(const Tchar * buf_,std::size_t size_)231 explicit CStringBufRefImpl(const Tchar * buf_, std::size_t size_)
232 : buf(buf_)
233 , size(size_) {
234 assert(size > 0);
235 }
236 CStringBufRefImpl(const CStringBufRefImpl &) = delete;
237 CStringBufRefImpl(CStringBufRefImpl &&) = default;
238 CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete;
239 CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete;
operator CString() const240 operator CString() const {
241 std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
242 return CString(buf, mpt::saturate_cast<int>(len));
243 }
244 };
245
246 template <typename Tchar, std::size_t size>
ReadCStringBuf(const std::array<Tchar,size> & buf)247 inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(const std::array<Tchar, size> & buf) {
248 return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf.data(), size);
249 }
250 template <typename Tchar, std::size_t size>
ReadCStringBuf(const Tchar (& buf)[size])251 inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(const Tchar (&buf)[size]) {
252 return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
253 }
254 template <typename Tchar>
ReadCStringBuf(const Tchar * buf,std::size_t size)255 inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(const Tchar * buf, std::size_t size) {
256 return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
257 }
258 template <typename Tchar, std::size_t size>
WriteCStringBuf(std::array<Tchar,size> & buf)259 inline CStringBufRefImpl<Tchar> WriteCStringBuf(std::array<Tchar, size> & buf) {
260 return CStringBufRefImpl<Tchar>(buf.data(), size);
261 }
262 template <typename Tchar, std::size_t size>
WriteCStringBuf(Tchar (& buf)[size])263 inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar (&buf)[size]) {
264 return CStringBufRefImpl<Tchar>(buf, size);
265 }
266 template <typename Tchar>
WriteCStringBuf(Tchar * buf,std::size_t size)267 inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar * buf, std::size_t size) {
268 return CStringBufRefImpl<Tchar>(buf, size);
269 }
270
271 #endif // MPT_DETECTED_MFC
272
273
274
275 template <std::size_t len>
276 struct charbuf {
277 public:
278 using Tchar = char;
279 using char_type = Tchar;
280 using string_type = std::basic_string<Tchar>;
281 using string_view_type = std::basic_string_view<Tchar>;
static_lengthmpt::MPT_INLINE_NS::charbuf282 constexpr std::size_t static_length() const {
283 return len;
284 }
285
286 public:
287 Tchar buf[len];
288
289 public:
charbufmpt::MPT_INLINE_NS::charbuf290 charbuf() {
291 std::fill(std::begin(buf), std::end(buf), Tchar('\0'));
292 }
293 charbuf(const charbuf &) = default;
294 charbuf(charbuf &&) = default;
295 charbuf & operator=(const charbuf &) = default;
296 charbuf & operator=(charbuf &&) = default;
operator []mpt::MPT_INLINE_NS::charbuf297 const Tchar & operator[](std::size_t i) const {
298 return buf[i];
299 }
strmpt::MPT_INLINE_NS::charbuf300 std::string str() const {
301 return static_cast<std::string>(*this);
302 }
operator string_typempt::MPT_INLINE_NS::charbuf303 operator string_type() const {
304 return mpt::ReadAutoBuf(buf);
305 }
operator string_view_typempt::MPT_INLINE_NS::charbuf306 explicit operator string_view_type() const {
307 return static_cast<string_view_type>(mpt::ReadAutoBuf(buf));
308 }
emptympt::MPT_INLINE_NS::charbuf309 bool empty() const {
310 return mpt::ReadAutoBuf(buf).empty();
311 }
operator =mpt::MPT_INLINE_NS::charbuf312 charbuf & operator=(const string_type & str) {
313 mpt::WriteAutoBuf(buf) = str;
314 return *this;
315 }
316
317 public:
operator !=(const charbuf & a,const charbuf & b)318 friend bool operator!=(const charbuf & a, const charbuf & b) {
319 return static_cast<string_view_type>(a) != static_cast<string_view_type>(b);
320 }
operator !=(const std::string & a,const charbuf & b)321 friend bool operator!=(const std::string & a, const charbuf & b) {
322 return a != static_cast<string_view_type>(b);
323 }
operator !=(const charbuf & a,const std::string & b)324 friend bool operator!=(const charbuf & a, const std::string & b) {
325 return static_cast<string_view_type>(a) != b;
326 }
operator ==(const charbuf & a,const charbuf & b)327 friend bool operator==(const charbuf & a, const charbuf & b) {
328 return static_cast<string_view_type>(a) == static_cast<string_view_type>(b);
329 }
operator ==(const std::string & a,const charbuf & b)330 friend bool operator==(const std::string & a, const charbuf & b) {
331 return a == static_cast<string_view_type>(b);
332 }
operator ==(const charbuf & a,const std::string & b)333 friend bool operator==(const charbuf & a, const std::string & b) {
334 return static_cast<string_view_type>(a) == b;
335 }
336 };
337
338
339 } // namespace MPT_INLINE_NS
340 } // namespace mpt
341
342
343
344 #endif // MPT_STRING_BUFFER_HPP
345