/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_BUFFER_HPP #define MPT_STRING_BUFFER_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string/types.hpp" #include #include #include #include #include #include #include #if MPT_DETECTED_MFC // cppcheck-suppress missingInclude #include #endif // MPT_DETECTED_MFC namespace mpt { inline namespace MPT_INLINE_NS { template class StringBufRefImpl { private: Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit StringBufRefImpl(Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type)); assert(size > 0); } StringBufRefImpl(const StringBufRefImpl &) = delete; StringBufRefImpl(StringBufRefImpl &&) = default; StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return std::basic_string_view(buf, buf + len); } bool empty() const { return buf[0] == Tchar('\0'); } StringBufRefImpl & operator=(const Tstring & str) { std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf); std::fill(buf + std::min(str.length(), size - 1), buf + size, Tchar('\0')); return *this; } }; template class StringBufRefImpl { private: const Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit StringBufRefImpl(const Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type)); assert(size > 0); } StringBufRefImpl(const StringBufRefImpl &) = delete; StringBufRefImpl(StringBufRefImpl &&) = default; StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return std::basic_string_view(buf, len); } bool empty() const { return buf[0] == Tchar('\0'); } }; template inline StringBufRefImpl::type> ReadTypedBuf(const std::array & buf) { return StringBufRefImpl::type>(buf.data(), size); } template inline StringBufRefImpl::type> ReadTypedBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>(buf, size); } template inline StringBufRefImpl::type> ReadTypedBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>(buf, size); } template inline StringBufRefImpl WriteTypedBuf(std::array & buf) { return StringBufRefImpl(buf.data(), size); } template inline StringBufRefImpl WriteTypedBuf(Tchar (&buf)[size]) { return StringBufRefImpl(buf, size); } template inline StringBufRefImpl WriteTypedBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl(buf, size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const std::array & buf) { return StringBufRefImpl::type>, typename std::add_const::type>(buf.data(), size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(std::array & buf) { return StringBufRefImpl::type>, Tchar>(buf.data(), size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(Tchar (&buf)[size]) { return StringBufRefImpl::type>, Tchar>(buf, size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl::type>, Tchar>(buf, size); } #if MPT_OS_WINDOWS template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const std::array & buf) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf.data(), size); } template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(std::array & buf) { return StringBufRefImpl::type>::string_type, Tchar>(buf.data(), size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(Tchar (&buf)[size]) { return StringBufRefImpl::type>::string_type, Tchar>(buf, size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl::type>::string_type, Tchar>(buf, size); } #endif // MPT_OS_WINDOWS #if MPT_DETECTED_MFC template class CStringBufRefImpl { private: Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit CStringBufRefImpl(Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { assert(size > 0); } CStringBufRefImpl(const CStringBufRefImpl &) = delete; CStringBufRefImpl(CStringBufRefImpl &&) = default; CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } CStringBufRefImpl & operator=(const CString & str) { std::copy(str.GetString(), str.GetString() + std::min(static_cast(str.GetLength()), size - 1), buf); std::fill(buf + std::min(static_cast(str.GetLength()), size - 1), buf + size, Tchar('\0')); return *this; } }; template class CStringBufRefImpl { private: const Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit CStringBufRefImpl(const Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { assert(size > 0); } CStringBufRefImpl(const CStringBufRefImpl &) = delete; CStringBufRefImpl(CStringBufRefImpl &&) = default; CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } }; template inline CStringBufRefImpl::type> ReadCStringBuf(const std::array & buf) { return CStringBufRefImpl::type>(buf.data(), size); } template inline CStringBufRefImpl::type> ReadCStringBuf(const Tchar (&buf)[size]) { return CStringBufRefImpl::type>(buf, size); } template inline CStringBufRefImpl::type> ReadCStringBuf(const Tchar * buf, std::size_t size) { return CStringBufRefImpl::type>(buf, size); } template inline CStringBufRefImpl WriteCStringBuf(std::array & buf) { return CStringBufRefImpl(buf.data(), size); } template inline CStringBufRefImpl WriteCStringBuf(Tchar (&buf)[size]) { return CStringBufRefImpl(buf, size); } template inline CStringBufRefImpl WriteCStringBuf(Tchar * buf, std::size_t size) { return CStringBufRefImpl(buf, size); } #endif // MPT_DETECTED_MFC template struct charbuf { public: using Tchar = char; using char_type = Tchar; using string_type = std::basic_string; using string_view_type = std::basic_string_view; constexpr std::size_t static_length() const { return len; } public: Tchar buf[len]; public: charbuf() { std::fill(std::begin(buf), std::end(buf), Tchar('\0')); } charbuf(const charbuf &) = default; charbuf(charbuf &&) = default; charbuf & operator=(const charbuf &) = default; charbuf & operator=(charbuf &&) = default; const Tchar & operator[](std::size_t i) const { return buf[i]; } std::string str() const { return static_cast(*this); } operator string_type() const { return mpt::ReadAutoBuf(buf); } explicit operator string_view_type() const { return static_cast(mpt::ReadAutoBuf(buf)); } bool empty() const { return mpt::ReadAutoBuf(buf).empty(); } charbuf & operator=(const string_type & str) { mpt::WriteAutoBuf(buf) = str; return *this; } public: friend bool operator!=(const charbuf & a, const charbuf & b) { return static_cast(a) != static_cast(b); } friend bool operator!=(const std::string & a, const charbuf & b) { return a != static_cast(b); } friend bool operator!=(const charbuf & a, const std::string & b) { return static_cast(a) != b; } friend bool operator==(const charbuf & a, const charbuf & b) { return static_cast(a) == static_cast(b); } friend bool operator==(const std::string & a, const charbuf & b) { return a == static_cast(b); } friend bool operator==(const charbuf & a, const std::string & b) { return static_cast(a) == b; } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_BUFFER_HPP