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