2023-02-04 15:03:54 +08:00
|
|
|
// require C++17+
|
2020-11-16 14:47:43 +08:00
|
|
|
#ifndef SIMDSOFT__NTCVT_HPP
|
|
|
|
#define SIMDSOFT__NTCVT_HPP
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#if !defined(WIN32_LEAN_AND_MEAN)
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
#endif
|
|
|
|
#include <Windows.h>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#if !defined(NTCVT_CP_DEFAULT)
|
2022-06-16 21:18:31 +08:00
|
|
|
#define NTCVT_CP_DEFAULT CP_UTF8
|
2020-11-16 14:47:43 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace ntcvt
|
|
|
|
{
|
|
|
|
|
|
|
|
// different with resize, not all of fill new memory with '\0'
|
|
|
|
namespace buffer_traits
|
|
|
|
{
|
|
|
|
template <class _Elem, class _Traits = std::char_traits<_Elem>,
|
|
|
|
class _Alloc = std::allocator<_Elem>>
|
2021-05-28 14:55:27 +08:00
|
|
|
class intrusive_string : public std::basic_string<_Elem, _Traits, _Alloc>
|
2020-11-16 14:47:43 +08:00
|
|
|
{
|
|
|
|
public:
|
2021-05-29 16:50:38 +08:00
|
|
|
#if _MSC_VER >= 1920 // VS2019+
|
2020-11-16 14:47:43 +08:00
|
|
|
using _Alty = std::_Rebind_alloc_t<_Alloc, _Elem>;
|
|
|
|
using _Alty_traits = std::allocator_traits<_Alty>;
|
|
|
|
|
|
|
|
using _Scary_val = std::_String_val<
|
|
|
|
std::conditional_t<std::_Is_simple_alloc_v<_Alty>, std::_Simple_types<_Elem>,
|
|
|
|
std::_String_iter_types<
|
|
|
|
_Elem, typename _Alty_traits::size_type,
|
|
|
|
typename _Alty_traits::difference_type, typename _Alty_traits::pointer,
|
|
|
|
typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;
|
|
|
|
#endif
|
|
|
|
// See also afxmfc CString::GetBufferSetLength
|
|
|
|
// Why do this hack?
|
|
|
|
// stupid: because the default c++ standard resize always fill with '\0'
|
|
|
|
// std::string: use memset (usually implemented with SIMD)
|
|
|
|
// std::wstring: for loop (slow performance)
|
|
|
|
// only works on msvc currently
|
2023-02-04 15:03:54 +08:00
|
|
|
_Elem* resize_for_overwrite(size_t len)
|
2020-11-16 14:47:43 +08:00
|
|
|
{
|
|
|
|
this->reserve(len);
|
2021-05-28 14:55:27 +08:00
|
|
|
#if _MSC_VER >= 1920 // VS2019+
|
2020-11-16 14:47:43 +08:00
|
|
|
std::_Compressed_pair<_Alty, _Scary_val>* _Myval =
|
|
|
|
(std::_Compressed_pair<_Alty, _Scary_val>*)this;
|
|
|
|
_Myval->_Myval2._Mysize = len;
|
|
|
|
auto front = &this->front();
|
|
|
|
front[len] = '\0';
|
|
|
|
return front;
|
|
|
|
#else
|
|
|
|
this->_Eos(len);
|
|
|
|
return &this->front();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-10-07 16:11:13 +08:00
|
|
|
template <typename _Cont> inline
|
|
|
|
auto prepare(_Cont& str, size_t size)
|
2020-11-16 14:47:43 +08:00
|
|
|
{
|
2022-10-07 16:11:13 +08:00
|
|
|
using _Elem = typename _Cont::value_type;
|
2021-05-28 14:55:27 +08:00
|
|
|
intrusive_string<_Elem>& helper = (intrusive_string<_Elem>&)str;
|
2023-02-04 15:03:54 +08:00
|
|
|
return helper.resize_for_overwrite(size);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
#if defined(_AFX)
|
2022-10-07 16:11:13 +08:00
|
|
|
template <> inline
|
|
|
|
auto prepare<CStringW>(CStringW& str, size_t size) {
|
|
|
|
return str.GetBufferSetLength(static_cast<int>(size));
|
|
|
|
}
|
|
|
|
template <> inline
|
|
|
|
auto prepare<CStringA>(CStringA& str, size_t size) {
|
|
|
|
return str.GetBufferSetLength(static_cast<int>(size));
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace buffer_traits
|
|
|
|
|
|
|
|
template <typename _StringContType>
|
|
|
|
inline _StringContType wcbs2a(const wchar_t* wcb, int len, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
if (len == -1)
|
|
|
|
len = lstrlenW(wcb);
|
|
|
|
_StringContType buffer;
|
|
|
|
int cch;
|
|
|
|
if (len > 0 && (cch = ::WideCharToMultiByte(cp, 0, wcb, len, NULL, 0, NULL, NULL)) > 0)
|
2021-05-28 14:55:27 +08:00
|
|
|
::WideCharToMultiByte(cp, 0, wcb, len, buffer_traits::prepare(buffer, cch), cch, NULL, NULL);
|
2020-11-16 14:47:43 +08:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename _StringContType>
|
|
|
|
inline _StringContType mcbs2w(const char* mcb, int len, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
if (len == -1)
|
|
|
|
len = lstrlenA(mcb);
|
|
|
|
_StringContType buffer;
|
|
|
|
int cch;
|
|
|
|
if (len > 0 && (cch = ::MultiByteToWideChar(cp, 0, mcb, len, NULL, 0)) > 0)
|
2021-05-28 14:55:27 +08:00
|
|
|
::MultiByteToWideChar(cp, 0, mcb, len, buffer_traits::prepare(buffer, cch), cch);
|
2020-11-16 14:47:43 +08:00
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int mcbs2w(const char* mcb, int len, wchar_t* wbuf, int wbuf_len, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
if (len == -1)
|
|
|
|
len = lstrlenA(mcb);
|
|
|
|
int cch;
|
|
|
|
if (len > 0 && (cch = ::MultiByteToWideChar(cp, 0, mcb, len, NULL, 0)) > 0)
|
|
|
|
return ::MultiByteToWideChar(cp, 0, mcb, len, wbuf, wbuf_len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline wchar_t* mcbs2wdup(const char* mcb, int len, int* wbuf_len, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
if (len == -1)
|
|
|
|
len = lstrlenA(mcb);
|
|
|
|
int cch;
|
|
|
|
if (len > 0 && (cch = ::MultiByteToWideChar(cp, 0, mcb, len, NULL, 0)) > 0)
|
|
|
|
{
|
|
|
|
wchar_t* wbuf = (wchar_t*)calloc(cch + 1, 2);
|
|
|
|
*wbuf_len = ::MultiByteToWideChar(cp, 0, mcb, len, wbuf, cch);
|
|
|
|
return wbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (wchar_t*)calloc(1, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _HAS_CXX17
|
|
|
|
inline std::string from_chars(const std::wstring_view& wcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2023-02-04 15:03:54 +08:00
|
|
|
return wcbs2a<std::string>(wcb.data(), static_cast<int>(wcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline std::wstring from_chars(const std::string_view& mcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2023-02-04 15:03:54 +08:00
|
|
|
return mcbs2w<std::wstring>(mcb.data(), static_cast<int>(mcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
inline std::string from_chars(const std::wstring& wcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2021-10-09 13:48:56 +08:00
|
|
|
return wcbs2a<std::string>(wcb.c_str(), static_cast<int>(wcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline std::wstring from_chars(const std::string& mcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2021-10-09 13:48:56 +08:00
|
|
|
return mcbs2w<std::wstring>(mcb.c_str(), static_cast<int>(mcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
inline std::string from_chars(const wchar_t* str, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
return wcbs2a<std::string>(str, -1, cp);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline std::wstring from_chars(const char* str, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
return mcbs2w<std::wstring>(str, -1, cp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ntcs or std::string to CStringW
|
|
|
|
#if defined(_AFX)
|
|
|
|
inline std::string from_chars(const CStringW& wcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
return wcbs2a<std::string>(wcb.GetString(), wcb.GetLength(), cp);
|
|
|
|
}
|
|
|
|
namespace afx
|
|
|
|
{
|
|
|
|
# if _HAS_CXX17
|
|
|
|
inline CStringW from_chars(std::string_view mcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2023-02-04 15:03:54 +08:00
|
|
|
return mcbs2w<CStringW>(mcb.data(), static_cast<int>(mcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
# else
|
|
|
|
inline CStringW from_chars(const char* str, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
|
|
|
return mcbs2w<CStringW>(str, -1, cp);
|
|
|
|
}
|
|
|
|
inline CStringW from_chars(const std::string& mcb, UINT cp = NTCVT_CP_DEFAULT)
|
|
|
|
{
|
2023-02-04 15:03:54 +08:00
|
|
|
return mcbs2w<CStringW>(mcb.c_str(), static_cast<int>(mcb.length()), cp);
|
2020-11-16 14:47:43 +08:00
|
|
|
}
|
|
|
|
# endif
|
|
|
|
} // namespace afx
|
|
|
|
#endif
|
|
|
|
} // namespace ntcvt
|
|
|
|
|
|
|
|
#endif
|