compat: add a simple std::ctype<char16_t> for OSX
Some checks failed
Doxygen Action / build (push) Has been cancelled

Standard C++ implementation has std::ctype<wchar_t> for UTF-32, but no
UTF-16 one. Since NSString is UTF-16, we need support for UTF-16 in C++
too if unnecessary translations between UTF-16/32 are to be avoided.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman
2025-09-15 12:11:59 +02:00
parent 4611976a42
commit 9df39583d6

View File

@@ -10,7 +10,10 @@
#include "windows.h"
#include <sal.h>
#include <tchar.h>
#else
#include <uchar.h>
#endif
#include <locale>
#include <type_traits>
#ifndef _In_
@@ -223,3 +226,108 @@ size_t _countof(const T (&arr)[N])
#define lockf64 lockf
#define ftruncate64 ftruncate
#endif
#ifndef _WIN32
// On Windows, wchar_t is UTF-16. On POSIX it is UTF32, and we are left out of UTF16 support in std C++.
namespace std
{
///
/// This is a poor man's instantiation of a `std::ctype<char16_t>`.
///
template <>
class ctype<char16_t> : public locale::facet, public ctype_base
{
public:
typedef char16_t char_type;
explicit ctype(size_t refs = 0) :
locale::facet(refs),
m_ctypew(std::use_facet<std::ctype<wchar_t>>(std::locale()))
{}
bool is(mask m, char_type c) const
{
return do_is(m, c);
}
const char_type* is(const char_type* low, const char_type* high, mask* vec) const
{
return do_is(low, high, vec);
}
const char_type* scan_is(mask m, const char_type* low, const char_type* high) const
{
return do_scan_is(m, low, high);
}
const char_type* scan_not(mask m, const char_type* low, const char_type* high) const
{
return do_scan_not(m, low, high);
}
char_type toupper(char_type c) const
{
return do_toupper(c);
}
const char_type* toupper(char_type* low, const char_type* high) const
{
return do_toupper(low, high);
}
char_type tolower(char_type c) const
{
return do_tolower(c);
}
const char_type* tolower(char_type* low, const char_type* high) const
{
return do_tolower(low, high);
}
char_type widen(char c) const
{
return do_widen(c);
}
const char* widen(const char* low, const char* high, char_type* to) const
{
return do_widen(low, high, to);
}
char narrow(char_type c, char dfault) const
{
return do_narrow(c, dfault);
}
const char_type* narrow(const char_type* low, const char_type* high, char dfault, char* to) const
{
return do_narrow(low, high, dfault, to);
}
static inline locale::id id;
protected:
const std::ctype<wchar_t> &m_ctypew;
bool do_is(mask m, char_type c) const { return m_ctypew.is(m, c); }
const char_type* do_is(const char_type* low, const char_type* high, mask* vec) const;
const char_type* do_scan_is(mask m, const char_type* low, const char_type* high) const;
const char_type* do_scan_not(mask m, const char_type* low, const char_type* high) const;
char_type do_toupper(char_type c) const { return m_ctypew.toupper(c); }
const char_type* do_toupper(char_type* low, const char_type* high) const;
char_type do_tolower(char_type c) const { return m_ctypew.tolower(c); }
const char_type* do_tolower(char_type* low, const char_type* high) const;
char_type do_widen(char) const;
const char* do_widen(const char* low, const char* high, char_type* dest) const;
char do_narrow(char_type, char dfault) const;
const char_type* do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const;
};
}
#endif