Compare commits

11 Commits

Author SHA1 Message Date
b79df0c65e refactor: continue refactor project from C++17 to 23 2025-07-25 10:49:07 +08:00
4f0b3d19d1 refactor: update C++ from 17 to 23 2025-07-25 09:35:26 +08:00
f014e54604 feat: update pycodec.
- rename encoding::utf to encoding::stlcvt.
- use uv to manage script and add pycodec generator script.
- update script in modern python.
- fix added pycodec generator.
2025-07-23 16:07:49 +08:00
821a592f02 feat: add various detector.
- add endian and compiler detector, and modify os detector.
- now we use CMake to add detector-used macro, instead of using some C++ features to detect them.
- change Windows environment detection according to the change of os detector.
2025-07-23 10:18:01 +08:00
6043609709 feat: finish windows encoding 2025-07-22 21:52:09 +08:00
53e8a77f47 feat: finish iconv module 2025-07-22 14:15:53 +08:00
6d44c7605b refactor: update encoding namespace
- add all essential functions prototypes in iconv encoding.
- add lost UTF convertion for windows encoding.
2025-07-21 20:36:26 +08:00
c2f6e29c36 feat: finish iconv kernel 2025-07-18 15:57:33 +08:00
c102964703 refactor: write iconv.
- write iconv encoding (not finished).
- rename united_codec to pycodec.
2025-07-15 16:17:59 +08:00
3605151caf refactor: finish Windows encoding namespace.
- finish Windows encoding namespace.
- add std::expected polyfill for help.
2025-07-14 15:06:33 +08:00
fa52d7416f refactor: condense the shared test data of parse and stringify. 2025-07-14 09:43:23 +08:00
83 changed files with 2868 additions and 1896 deletions

View File

@ -117,7 +117,7 @@ BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: false
BreakTemplateDeclarations: Yes
ColumnLimit: 100
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
@ -206,7 +206,7 @@ RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortIncludes: Never
SortJavaStaticImport: Before
SortUsingDeclarations: Lexicographic
SpaceAfterCStyleCast: true

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# -------------------- Output --------------------
out/
src/YYCC/YYCCVersion.hpp
src/yycc/version.hpp
CMakeSettings.json
# -------------------- VSCode --------------------

View File

@ -4,10 +4,15 @@ project(YYCC
LANGUAGES CXX
)
# Setup C++ standard
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Provide options
option(YYCC_BUILD_TESTBENCH "Build testbench of YYCCommonplace." OFF)
option(YYCC_BUILD_DOC "Build document of YYCCommonplace." OFF)
option(YYCC_DEBUG_UE_FILTER "YYCC developer used switch for testing Windows unhandled exception filter. Should not set to ON!!!" OFF)
option(YYCC_ENFORCE_ICONV "Enforce iconv support for this library (e.g. in MSYS2 environment)." OFF)
# Setup install path from CMake provided install path for convenient use.
include(GNUInstallDirs)
@ -27,6 +32,10 @@ if (YYCC_BUILD_TESTBENCH)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
find_package(GTest REQUIRED)
endif ()
# Iconv is required if we are not in Windows or user request it
if (YYCC_ENFORCE_ICONV OR (NOT WIN32))
find_package(Iconv REQUIRED)
endif ()
# Import 3 build targets
add_subdirectory(src)

View File

@ -73,7 +73,7 @@ Assume \c blabla() function is Windows specific.
We have following example code:
\code
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
blabla();
#endif
\endcode

View File

@ -11,7 +11,7 @@ Due to legacy reason, Windows defines various things which are not compatible wi
YYCC has a way to solve the issue introduced above.
\code
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include <WinImportPrefix.hpp>
#include <Windows.h>
#include "other_header_depend_on_windows.h"

215
script/.gitignore vendored
View File

@ -1,3 +1,216 @@
# -------------------- Output --------------------
## ===== Myself =====
# Exclude VSCode
.vscode/
# Exclude generated files
win_build.bat
linux_build.sh
## ===== Python =====
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
#poetry.toml
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/
# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/
# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore
# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/

View File

@ -1,15 +1,16 @@
import jinja2
import argparse
import os
import io
import typing
import re
import shlex
from pathlib import Path
from dataclasses import dataclass
import jinja2
def validate_cpp_ver(ver: str) -> str:
if re.match(r'^[0-9]+$', ver) is not None: return ver
else: raise argparse.ArgumentTypeError('invalid version of C++ standard.')
def write_line(f: io.TextIOWrapper, val: str) -> None:
def write_line(f: typing.TextIO, val: str) -> None:
f.write(val)
f.write('\n')
@ -24,55 +25,51 @@ def escape_cmd_argument(arg):
def escape_sh_argument(arg):
return shlex.quote(arg)
@dataclass
class ScriptSettings:
m_CppVersion: str
m_BuildDoc: bool
m_PIC: bool
def __init__(self, cpp_ver: str, build_doc: bool, pic: bool):
self.m_CppVersion = cpp_ver
self.m_BuildDoc = build_doc
self.m_PIC = pic
cpp_version: str
build_doc: bool
pic: bool
class TemplateRender:
m_Loader: jinja2.BaseLoader
m_Environment: jinja2.Environment
loader: jinja2.BaseLoader
environment: jinja2.Environment
m_WinTemplate: jinja2.Template
m_LinuxTemplate: jinja2.Template
win_template: jinja2.Template
linux_template: jinja2.Template
m_Settings: ScriptSettings
settings: ScriptSettings
def __init__(self, settings: ScriptSettings) -> None:
self.m_Loader = jinja2.FileSystemLoader(self.__get_dir())
self.m_Environment = jinja2.Environment(loader=self.m_Loader)
self.loader = jinja2.FileSystemLoader(self.__get_dir())
self.environment = jinja2.Environment(loader=self.loader)
self.m_WinTemplate = self.m_Environment.get_template('win_build.template.bat')
self.m_LinuxTemplate = self.m_Environment.get_template('linux_build.template.sh')
self.win_template = self.environment.get_template('win_build.bat.jinja')
self.linux_template = self.environment.get_template('linux_build.sh.jinja')
self.m_Settings = settings
self.settings = settings
def __get_dir(self) -> str:
return os.path.dirname(__file__)
def __get_dir(self) -> Path:
return Path(__file__).resolve().parent
def __escape_path(self, val: str, is_win: bool) -> str:
if is_win: return escape_cmd_argument(val)
else: return escape_sh_argument(val)
def __render(self, template: jinja2.Template, dest_file: str, is_win: bool) -> None:
with open(os.path.join(self.__get_dir(), dest_file), 'w', encoding='utf-8') as f:
with open(self.__get_dir() / dest_file, 'w', encoding='utf-8') as f:
f.write(template.render(
repo_root_dir = self.__escape_path(os.path.dirname(self.__get_dir()), is_win),
cpp_version = self.m_Settings.m_CppVersion,
build_doc = self.m_Settings.m_BuildDoc,
pic = settings.m_PIC
repo_root_dir = self.__escape_path(str(self.__get_dir().parent), is_win),
cpp_version = self.settings.cpp_version,
build_doc = self.settings.build_doc,
pic = settings.pic
))
def render_win_script(self) -> None:
self.__render(self.m_WinTemplate, 'win_build.bat', True)
self.__render(self.win_template, 'win_build.bat', True)
def render_linux_script(self) -> None:
self.__render(self.m_LinuxTemplate, 'linux_build.sh', False)
self.__render(self.linux_template, 'linux_build.sh', False)
if __name__ == '__main__':

2
script/pycodec/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Exclude result
*.cpp

View File

@ -0,0 +1,63 @@
import typing
from pathlib import Path
import os
class LanguageToken:
name: str
alias: tuple[str, ...]
code_page: str | None
iconv_code: str | None
def __init__(self, name: str, alias: typing.Iterator[str], code_page: str, iconv_code: str):
self.name = name.lower()
self.alias = tuple(map(lambda x: x.lower(), alias))
self.code_page = None if code_page == '' else code_page
self.iconv_code = None if iconv_code == '' else iconv_code
def extract_data(fs: typing.TextIO) -> list[str]:
# remove first line to remove table header
return fs.readlines()[1:]
def extract_token(csv_data: list[str]) -> tuple[LanguageToken, ...]:
ret: list[LanguageToken] = []
for line in csv_data:
line = line.strip('\n')
line_sp = line.split('\t')
alias_sp = filter(lambda x: len(x) != 0, map(lambda x: x.strip(), line_sp[1].split(',')))
ret.append(LanguageToken(line_sp[0], alias_sp, line_sp[2], line_sp[3]))
return tuple(ret)
def write_alias_map(fs: typing.TextIO, data: tuple[LanguageToken, ...]) -> None:
fs.write('static const std::map<NS_YYCC_STRING::u8string, NS_YYCC_STRING::u8string> ALISA_MAP {\n')
for i in data:
for j in i.alias:
fs.write(f'\t{{ YYCC_U8("{j}"), YYCC_U8("{i.name}") }},\n')
fs.write('};\n')
def write_win_cp_map(fs: typing.TextIO, data: tuple[LanguageToken, ...]) -> None:
fs.write('static const std::map<NS_YYCC_STRING::u8string, CodePage> WINCP_MAP {\n')
for i in data:
if i.code_page is not None:
fs.write(f'\t{{ YYCC_U8("{i.name}"), static_cast<CodePage>({i.code_page}u) }},\n')
fs.write('};\n')
def write_iconv_map(fs: typing.TextIO, data: tuple[LanguageToken, ...]) -> None:
fs.write('static const std::map<NS_YYCC_STRING::u8string, std::string> ICONV_MAP {\n')
for i in data:
if i.iconv_code is not None:
fs.write(f'\t{{ YYCC_U8("{i.name}"), "{i.iconv_code}" }},\n')
fs.write('};\n')
if __name__ == '__main__':
# get file path
self_path = Path(__file__).resolve().parent
csv_file = self_path / 'encoding_table.csv'
cpp_file = self_path / 'encoding_table.cpp'
# process files
with open(csv_file, 'r', encoding='utf-8') as fr:
with open(cpp_file, 'w', encoding='utf-8') as fw:
data = extract_data(fr)
token = extract_token(data)
write_alias_map(fw, token)
write_win_cp_map(fw, token)
write_iconv_map(fw, token)

View File

@ -0,0 +1,98 @@
Encoding Alias Code Page Iconv Identifier
ascii 646, us-ascii 437 ASCII
big5 big5-tw, csbig5 950 BIG5
big5hkscs big5-hkscs, hkscs BIG5-HKSCS
cp037 IBM037, IBM039 037
cp273 273, IBM273, csIBM273
cp424 EBCDIC-CP-HE, IBM424
cp437 437, IBM437 437
cp500 EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 500
cp720 720
cp737 737
cp775 IBM775 775
cp850 850, IBM850 850 CP850
cp852 852, IBM852 852
cp855 855, IBM855 855
cp856
cp857 857, IBM857 857
cp858 858, IBM858 858
cp860 860, IBM860 860
cp861 861, CP-IS, IBM861 861
cp862 862, IBM862 862 CP862
cp863 863, IBM863 863
cp864 IBM864 864
cp865 865, IBM865 865
cp866 866, IBM866 866 CP866
cp869 869, CP-GR, IBM869 869
cp874 874 CP874
cp875 875
cp932 932, ms932, mskanji, ms-kanji, windows-31j 932 CP932
cp949 949, ms949, uhc 949 CP949
cp950 950, ms950 950 CP950
cp1006
cp1026 ibm1026 1026
cp1125 1125, ibm1125, cp866u, ruscii
cp1140 ibm1140 1140
cp1250 windows-1250 1250 CP1250
cp1251 windows-1251 1251 CP1251
cp1252 windows-1252 1252 CP1252
cp1253 windows-1253 1253 CP1253
cp1254 windows-1254 1254 CP1254
cp1255 windows-1255 1255 CP1255
cp1256 windows-1256 1256 CP1256
cp1257 windows-1257 1257 CP1257
cp1258 windows-1258 1258 CP1258
euc_jp eucjp, ujis, u-jis 20932 EUC-JP
euc_jis_2004 jisx0213, eucjis2004
euc_jisx0213 eucjisx0213
euc_kr euckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001 51949 EUC-KR
gb2312 chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58 936 CP936
gbk 936, cp936, ms936 936 GBK
gb18030 gb18030-2000 54936 GB18030
hz hzgb, hz-gb, hz-gb-2312 52936 HZ
iso2022_jp csiso2022jp, iso2022jp, iso-2022-jp 50220 ISO-2022-JP
iso2022_jp_1 iso2022jp-1, iso-2022-jp-1 ISO-2022-JP-1
iso2022_jp_2 iso2022jp-2, iso-2022-jp-2 ISO-2022-JP-2
iso2022_jp_2004 iso2022jp-2004, iso-2022-jp-2004
iso2022_jp_3 iso2022jp-3, iso-2022-jp-3
iso2022_jp_ext iso2022jp-ext, iso-2022-jp-ext
iso2022_kr csiso2022kr, iso2022kr, iso-2022-kr 50225 ISO-2022-KR
latin_1 iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 28591 ISO-8859-1
iso8859_2 iso-8859-2, latin2, L2 28592 ISO-8859-2
iso8859_3 iso-8859-3, latin3, L3 28593 ISO-8859-3
iso8859_4 iso-8859-4, latin4, L4 28594 ISO-8859-4
iso8859_5 iso-8859-5, cyrillic 28595 ISO-8859-5
iso8859_6 iso-8859-6, arabic 28596 ISO-8859-6
iso8859_7 iso-8859-7, greek, greek8 28597 ISO-8859-7
iso8859_8 iso-8859-8, hebrew 28598 ISO-8859-8
iso8859_9 iso-8859-9, latin5, L5 28599 ISO-8859-9
iso8859_10 iso-8859-10, latin6, L6 ISO-8859-10
iso8859_11 iso-8859-11, thai ISO-8859-11
iso8859_13 iso-8859-13, latin7, L7 28603 ISO-8859-13
iso8859_14 iso-8859-14, latin8, L8 ISO-8859-14
iso8859_15 iso-8859-15, latin9, L9 28605 ISO-8859-15
iso8859_16 iso-8859-16, latin10, L10 ISO-8859-16
johab cp1361, ms1361 1361 JOHAB
koi8_r
koi8_t KOI8-T
koi8_u
kz1048 kz_1048, strk1048_2002, rk1048
mac_cyrillic maccyrillic 10007 MacCyrillic
mac_greek macgreek 10006 MacGreek
mac_iceland maciceland 10079 MacIceland
mac_latin2 maclatin2, maccentraleurope, mac_centeuro
mac_roman macroman, macintosh MacRoman
mac_turkish macturkish 10081 MacTurkish
ptcp154 csptcp154, pt154, cp154, cyrillic-asian PT154
shift_jis csshiftjis, shiftjis, sjis, s_jis 932 SHIFT_JIS
shift_jis_2004 shiftjis2004, sjis_2004, sjis2004
shift_jisx0213 shiftjisx0213, sjisx0213, s_jisx0213
utf_32 U32, utf32 UTF-32
utf_32_be UTF-32BE UTF-32BE
utf_32_le UTF-32LE UTF-32LE
utf_16 U16, utf16 UTF16
utf_16_be UTF-16BE UTF-16BE
utf_16_le UTF-16LE UTF-16LE
utf_7 U7, unicode-1-1-utf-7 65000 UTF-7
utf_8 U8, UTF, utf8, utf-8, cp65001 65001 UTF-8
utf_8_sig
1 Encoding Alias Code Page Iconv Identifier
2 ascii 646, us-ascii 437 ASCII
3 big5 big5-tw, csbig5 950 BIG5
4 big5hkscs big5-hkscs, hkscs BIG5-HKSCS
5 cp037 IBM037, IBM039 037
6 cp273 273, IBM273, csIBM273
7 cp424 EBCDIC-CP-HE, IBM424
8 cp437 437, IBM437 437
9 cp500 EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 500
10 cp720 720
11 cp737 737
12 cp775 IBM775 775
13 cp850 850, IBM850 850 CP850
14 cp852 852, IBM852 852
15 cp855 855, IBM855 855
16 cp856
17 cp857 857, IBM857 857
18 cp858 858, IBM858 858
19 cp860 860, IBM860 860
20 cp861 861, CP-IS, IBM861 861
21 cp862 862, IBM862 862 CP862
22 cp863 863, IBM863 863
23 cp864 IBM864 864
24 cp865 865, IBM865 865
25 cp866 866, IBM866 866 CP866
26 cp869 869, CP-GR, IBM869 869
27 cp874 874 CP874
28 cp875 875
29 cp932 932, ms932, mskanji, ms-kanji, windows-31j 932 CP932
30 cp949 949, ms949, uhc 949 CP949
31 cp950 950, ms950 950 CP950
32 cp1006
33 cp1026 ibm1026 1026
34 cp1125 1125, ibm1125, cp866u, ruscii
35 cp1140 ibm1140 1140
36 cp1250 windows-1250 1250 CP1250
37 cp1251 windows-1251 1251 CP1251
38 cp1252 windows-1252 1252 CP1252
39 cp1253 windows-1253 1253 CP1253
40 cp1254 windows-1254 1254 CP1254
41 cp1255 windows-1255 1255 CP1255
42 cp1256 windows-1256 1256 CP1256
43 cp1257 windows-1257 1257 CP1257
44 cp1258 windows-1258 1258 CP1258
45 euc_jp eucjp, ujis, u-jis 20932 EUC-JP
46 euc_jis_2004 jisx0213, eucjis2004
47 euc_jisx0213 eucjisx0213
48 euc_kr euckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001 51949 EUC-KR
49 gb2312 chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58 936 CP936
50 gbk 936, cp936, ms936 936 GBK
51 gb18030 gb18030-2000 54936 GB18030
52 hz hzgb, hz-gb, hz-gb-2312 52936 HZ
53 iso2022_jp csiso2022jp, iso2022jp, iso-2022-jp 50220 ISO-2022-JP
54 iso2022_jp_1 iso2022jp-1, iso-2022-jp-1 ISO-2022-JP-1
55 iso2022_jp_2 iso2022jp-2, iso-2022-jp-2 ISO-2022-JP-2
56 iso2022_jp_2004 iso2022jp-2004, iso-2022-jp-2004
57 iso2022_jp_3 iso2022jp-3, iso-2022-jp-3
58 iso2022_jp_ext iso2022jp-ext, iso-2022-jp-ext
59 iso2022_kr csiso2022kr, iso2022kr, iso-2022-kr 50225 ISO-2022-KR
60 latin_1 iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 28591 ISO-8859-1
61 iso8859_2 iso-8859-2, latin2, L2 28592 ISO-8859-2
62 iso8859_3 iso-8859-3, latin3, L3 28593 ISO-8859-3
63 iso8859_4 iso-8859-4, latin4, L4 28594 ISO-8859-4
64 iso8859_5 iso-8859-5, cyrillic 28595 ISO-8859-5
65 iso8859_6 iso-8859-6, arabic 28596 ISO-8859-6
66 iso8859_7 iso-8859-7, greek, greek8 28597 ISO-8859-7
67 iso8859_8 iso-8859-8, hebrew 28598 ISO-8859-8
68 iso8859_9 iso-8859-9, latin5, L5 28599 ISO-8859-9
69 iso8859_10 iso-8859-10, latin6, L6 ISO-8859-10
70 iso8859_11 iso-8859-11, thai ISO-8859-11
71 iso8859_13 iso-8859-13, latin7, L7 28603 ISO-8859-13
72 iso8859_14 iso-8859-14, latin8, L8 ISO-8859-14
73 iso8859_15 iso-8859-15, latin9, L9 28605 ISO-8859-15
74 iso8859_16 iso-8859-16, latin10, L10 ISO-8859-16
75 johab cp1361, ms1361 1361 JOHAB
76 koi8_r
77 koi8_t KOI8-T
78 koi8_u
79 kz1048 kz_1048, strk1048_2002, rk1048
80 mac_cyrillic maccyrillic 10007 MacCyrillic
81 mac_greek macgreek 10006 MacGreek
82 mac_iceland maciceland 10079 MacIceland
83 mac_latin2 maclatin2, maccentraleurope, mac_centeuro
84 mac_roman macroman, macintosh MacRoman
85 mac_turkish macturkish 10081 MacTurkish
86 ptcp154 csptcp154, pt154, cp154, cyrillic-asian PT154
87 shift_jis csshiftjis, shiftjis, sjis, s_jis 932 SHIFT_JIS
88 shift_jis_2004 shiftjis2004, sjis_2004, sjis2004
89 shift_jisx0213 shiftjisx0213, sjisx0213, s_jisx0213
90 utf_32 U32, utf32 UTF-32
91 utf_32_be UTF-32BE UTF-32BE
92 utf_32_le UTF-32LE UTF-32LE
93 utf_16 U16, utf16 UTF16
94 utf_16_be UTF-16BE UTF-16BE
95 utf_16_le UTF-16LE UTF-16LE
96 utf_7 U7, unicode-1-1-utf-7 65000 UTF-7
97 utf_8 U8, UTF, utf8, utf-8, cp65001 65001 UTF-8
98 utf_8_sig

7
script/pyproject.toml Normal file
View File

@ -0,0 +1,7 @@
[project]
name = "script"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"jinja2==3.1.2",
]

74
script/uv.lock generated Normal file
View File

@ -0,0 +1,74 @@
version = 1
revision = 2
requires-python = ">=3.11"
[[package]]
name = "jinja2"
version = "3.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/ff/75c28576a1d900e87eb6335b063fab47a8ef3c8b4d88524c4bf78f670cce/Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", size = 268239, upload-time = "2022-04-28T17:21:27.579Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bc/c3/f068337a370801f372f2f8f6bad74a5c140f6fda3d9de154052708dd3c65/Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61", size = 133101, upload-time = "2022-04-28T17:21:25.336Z" },
]
[[package]]
name = "markupsafe"
version = "3.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" },
{ url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" },
{ url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" },
{ url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" },
{ url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" },
{ url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" },
{ url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" },
{ url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" },
{ url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" },
{ url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" },
{ url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" },
{ url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" },
{ url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" },
{ url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" },
{ url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" },
{ url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" },
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" },
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" },
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" },
{ url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" },
{ url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" },
{ url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" },
{ url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" },
{ url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" },
{ url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" },
{ url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" },
{ url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" },
{ url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" },
{ url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" },
{ url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" },
{ url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" },
{ url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" },
{ url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" },
{ url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" },
{ url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" },
{ url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" },
{ url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" },
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
]
[[package]]
name = "script"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "jinja2" },
]
[package.metadata]
requires-dist = [{ name = "jinja2", specifier = "==3.1.2" }]

View File

@ -14,24 +14,10 @@ PRIVATE
yycc/string/reinterpret.cpp
yycc/string/op.cpp
yycc/rust/panic.cpp
yycc/patch/path.cpp
yycc/encoding/utf.cpp
yycc/encoding/stlcvt.cpp
yycc/encoding/windows.cpp
yycc/encoding/iconv.cpp
yycc/encoding/united_codec.cpp
# YYCC/COMHelper.cpp
# YYCC/ArgParser.cpp
# YYCC/ConfigManager.cpp
# YYCC/ConsoleHelper.cpp
# YYCC/DialogHelper.cpp
# YYCC/EncodingHelper.cpp
# YYCC/ExceptionHelper.cpp
# YYCC/StdPatch.cpp
# YYCC/IOHelper.cpp
# YYCC/StringHelper.cpp
# YYCC/WinFctHelper.cpp
# # Natvis (only for MSVC)
# $<$<CXX_COMPILER_ID:MSVC>:YYCC.natvis>
yycc/encoding/pycodec.cpp
)
target_sources(YYCCommonplace
PUBLIC
@ -40,60 +26,28 @@ FILES
# Headers
yycc.hpp
yycc/version.hpp
yycc/prelude/core.hpp
yycc/prelude/rust.hpp
yycc/macro/version_cmp.hpp
yycc/macro/feature_probe.hpp
yycc/macro/os_detector.hpp
yycc/macro/endian_detector.hpp
yycc/macro/compiler_detector.hpp
yycc/macro/class_copy_move.hpp
yycc/string.hpp
yycc/string/reinterpret.hpp
yycc/string/op.hpp
yycc/num/parse.hpp
yycc/num/stringify.hpp
yycc/rust/prelude.hpp
yycc/rust/primitive.hpp
yycc/rust/panic.hpp
yycc/rust/option.hpp
yycc/rust/result.hpp
yycc/rust/num/parse.hpp
yycc/rust/num/stringify.hpp
yycc/windows/unsafe_suppressor.hpp
yycc/windows/import_guard_head.hpp
yycc/windows/import_guard_tail.hpp
yycc/constraint.hpp
yycc/constraint/builder.hpp
yycc/patch/path.hpp
yycc/patch/contains.hpp
yycc/patch/starts_ends_with.hpp
yycc/encoding/utf.hpp
yycc/encoding/stlcvt.hpp
yycc/encoding/windows.hpp
yycc/encoding/iconv.hpp
yycc/encoding/united_codec.hpp
# # Headers
# # Common headers
# YYCC/Constraints.hpp
# YYCC/COMHelper.hpp
# YYCC/ArgParser.hpp
# YYCC/ConfigManager.hpp
# YYCC/ConsoleHelper.hpp
# YYCC/DialogHelper.hpp
# YYCC/EncodingHelper.hpp
# YYCC/EnumHelper.hpp
# YYCC/ExceptionHelper.hpp
# YYCC/StdPatch.hpp
# YYCC/IOHelper.hpp
# YYCC/ParserHelper.hpp
# YYCC/StringHelper.hpp
# YYCC/WinFctHelper.hpp
# # Windows including guard pair
# YYCC/WinImportPrefix.hpp
# YYCC/WinImportSuffix.hpp
# # Internal
# YYCC/YYCCVersion.hpp
# YYCC/YYCCInternal.hpp
# # Exposed
# YYCCommonplace.hpp
yycc/encoding/pycodec.hpp
)
# Setup header infomations
target_include_directories(YYCCommonplace
@ -101,30 +55,53 @@ PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
# Link Iconv if we have import it
if (Iconv_FOUND)
target_link_libraries(YYCCommonplace
PRIVATE
Iconv::Iconv
)
endif ()
# Link with DbgHelp.lib on Windows
target_link_libraries(YYCCommonplace
PRIVATE
$<$<BOOL:${WIN32}>:DbgHelp.lib>
)
# Setup C++ standard
target_compile_features(YYCCommonplace PUBLIC cxx_std_17)
set_target_properties(YYCCommonplace PROPERTIES CXX_EXTENSION OFF)
# Setup macros
target_compile_definitions(YYCCommonplace
# Debug macro should populate to child projects
PUBLIC
$<$<BOOL:${YYCC_DEBUG_UE_FILTER}>:YYCC_DEBUG_UE_FILTER>
# Unicode charset for private using
PRIVATE
# Iconv environment macro
$<$<BOOL:${YYCC_ENFORCE_ICONV}>:YYCC_FEAT_ICONV>
# OS macro
$<$<BOOL:${WIN32}>:YYCC_OS_WINDOWS>
$<$<PLATFORM_ID:Linux>:YYCC_OS_LINUX>
# Compiler macro
$<$<CXX_COMPILER_ID:GNU>:YYCC_CC_GCC>
$<$<CXX_COMPILER_ID:Clang>:YYCC_CC_CLANG>
$<$<CXX_COMPILER_ID:MSVC>:YYCC_CC_MSVC>
# Endian macro
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},LITTLE_ENDIAN>:YYCC_ENDIAN_LITTLE>
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN>:YYCC_ENDIAN_BIG>
# Use Unicode charset on MSVC
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
# Fix MSVC shit
$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_DEPRECATE>
$<$<CXX_COMPILER_ID:MSVC>:_CRT_NONSTDC_NO_WARNINGS>
$<$<CXX_COMPILER_ID:MSVC>:_CRT_NONSTDC_NO_DEPRECATE>
# Fix Windows header file shit
$<$<BOOL:${WIN32}>:WIN32_LEAN_AND_MEAN>
$<$<BOOL:${WIN32}>:NOMINMAX>
)
target_compile_options(YYCCommonplace
# Order build as UTF-8 in MSVC
PRIVATE
PUBLIC
# Order build as UTF-8 in MSVC
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
)
# TODO: Fix GCC stacktrace link issue
# Install binary and headers
install(TARGETS YYCCommonplace
EXPORT YYCCommonplaceTargets

View File

@ -3,7 +3,7 @@
#include "EncodingHelper.hpp"
#include "ConsoleHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp"
#include <Windows.h>
#include <shellapi.h>
@ -24,7 +24,7 @@ namespace YYCC::ArgParser {
return ArgumentList(std::move(args));
}
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
ArgumentList ArgumentList::CreateFromWin32() {
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw

View File

@ -37,7 +37,7 @@ namespace YYCC::ArgParser {
* and should not be seen as a part of arguments.
*/
static ArgumentList CreateFromStd(int argc, char* argv[]);
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
/**
* @brief Create argument list from Win32 function.
* @details

View File

@ -1,5 +1,5 @@
#include "COMHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
namespace YYCC::COMHelper {

View File

@ -1,6 +1,6 @@
#pragma once
#include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include <memory>

View File

@ -5,7 +5,7 @@
#include <iostream>
// Include Windows used headers in Windows.
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp"
#include <Windows.h>
#include <io.h>
@ -16,7 +16,7 @@
namespace YYCC::ConsoleHelper {
#pragma region Windows Specific Functions
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
static bool RawEnableColorfulConsole(FILE* fs) {
if (!_isatty(_fileno(fs))) return false;
@ -161,7 +161,7 @@ namespace YYCC::ConsoleHelper {
#pragma endregion
bool EnableColorfulConsole() {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
bool ret = true;
ret &= RawEnableColorfulConsole(stdout);
@ -177,7 +177,7 @@ namespace YYCC::ConsoleHelper {
}
yycc_u8string ReadLine() {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
// get stdin mode
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
@ -221,7 +221,7 @@ namespace YYCC::ConsoleHelper {
strl += YYCC_U8("\n");
}
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
// call Windows specific writer
WinConsoleWrite(strl, bIsErr);
#else

View File

@ -1,5 +1,5 @@
#include "DialogHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "EncodingHelper.hpp"
#include "StringHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once
#include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "COMHelper.hpp"
#include <string>

View File

@ -1,209 +0,0 @@
#include "EncodingHelper.hpp"
#include <locale>
namespace YYCC::EncodingHelper {
/* Define some assistant macros for easy writing. */
#define CONVFCT_TYPE2(fct_name, src_char_type, dst_char_type, ...) if (src == nullptr) return false; \
std::basic_string_view<src_char_type> cache(src); \
return fct_name(cache, dst, ##__VA_ARGS__);
#define CONVFCT_TYPE3(fct_name, src_char_type, dst_char_type, ...) std::basic_string<dst_char_type> ret; \
if (!fct_name(src, ret, ##__VA_ARGS__)) ret.clear(); \
return ret;
#define CONVFCT_TYPE4(fct_name, src_char_type, dst_char_type, ...) std::basic_string<dst_char_type> ret; \
if (!fct_name(src, ret, ##__VA_ARGS__)) ret.clear(); \
return ret;
#if YYCC_OS == YYCC_OS_WINDOWS
#pragma region WcharToChar
bool WcharToChar(const std::wstring_view& src, std::string& dst, UINT code_page) {
// if src is empty, direct output
if (src.empty()) {
dst.clear();
return true;
}
// init WideCharToMultiByte used variables
// setup src pointer
LPCWCH lpWideCharStr = reinterpret_cast<LPCWCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return false;
int cchWideChar = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
if (desired_size <= 0) return false;
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result = WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, reinterpret_cast<LPSTR>(dst.data()), desired_size, NULL, NULL);
if (write_result <= 0) return false;
return true;
}
bool WcharToChar(const wchar_t* src, std::string& dst, UINT code_page) {
CONVFCT_TYPE2(WcharToChar, wchar_t, char, code_page);
}
std::string WcharToChar(const std::wstring_view& src, UINT code_page) {
CONVFCT_TYPE3(WcharToChar, wchar_t, char, code_page);
}
std::string WcharToChar(const wchar_t* src, UINT code_page) {
CONVFCT_TYPE4(WcharToChar, wchar_t, char, code_page);
}
#pragma endregion
#pragma region CharToWchar
bool CharToWchar(const std::string_view& src, std::wstring& dst, UINT code_page) {
// if src is empty, direct output
if (src.empty()) {
dst.clear();
return true;
}
// init WideCharToMultiByte used variables
// setup src pointer
LPCCH lpMultiByteStr = reinterpret_cast<LPCCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return false;
int cbMultiByte = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, NULL, 0);
if (desired_size <= 0) return false;
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, reinterpret_cast<LPWSTR>(dst.data()), desired_size);
if (write_result <= 0) return false;
return true;
}
bool CharToWchar(const char* src, std::wstring& dst, UINT code_page) {
CONVFCT_TYPE2(CharToWchar, char, wchar_t, code_page);
}
std::wstring CharToWchar(const std::string_view& src, UINT code_page) {
CONVFCT_TYPE3(CharToWchar, char, wchar_t, code_page);
}
std::wstring CharToWchar(const char* src, UINT code_page) {
CONVFCT_TYPE4(CharToWchar, char, wchar_t, code_page);
}
#pragma endregion
#pragma region CharToChar
bool CharToChar(const std::string_view& src, std::string& dst, UINT src_code_page, UINT dst_code_page) {
std::wstring intermediary;
if (!CharToWchar(src, intermediary, src_code_page)) return false;
if (!WcharToChar(intermediary, dst, dst_code_page)) return false;
return true;
}
bool CharToChar(const char* src, std::string& dst, UINT src_code_page, UINT dst_code_page) {
CONVFCT_TYPE2(CharToChar, char, char, src_code_page, dst_code_page);
}
std::string CharToChar(const std::string_view& src, UINT src_code_page, UINT dst_code_page) {
CONVFCT_TYPE3(CharToChar, char, char, src_code_page, dst_code_page);
}
std::string CharToChar(const char* src, UINT src_code_page, UINT dst_code_page) {
CONVFCT_TYPE4(CharToChar, char, char, src_code_page, dst_code_page);
}
#pragma endregion
#pragma region WcharToUTF8
bool WcharToUTF8(const std::wstring_view& src, yycc_u8string& dst) {
std::string adapted_dst;
bool ret = WcharToChar(src, adapted_dst, CP_UTF8);
if (ret) dst = ToUTF8(adapted_dst);
return ret;
}
bool WcharToUTF8(const wchar_t* src, yycc_u8string& dst) {
CONVFCT_TYPE2(WcharToUTF8, wchar_t, yycc_char8_t);
}
yycc_u8string WcharToUTF8(const std::wstring_view& src) {
CONVFCT_TYPE3(WcharToUTF8, wchar_t, yycc_char8_t);
}
yycc_u8string WcharToUTF8(const wchar_t* src) {
CONVFCT_TYPE4(WcharToUTF8, wchar_t, yycc_char8_t);
}
#pragma endregion
#pragma region UTF8ToWchar
bool UTF8ToWchar(const yycc_u8string_view& src, std::wstring& dst) {
std::string_view adapted_src(ToOrdinaryView(src));
return CharToWchar(adapted_src, dst, CP_UTF8);
}
bool UTF8ToWchar(const yycc_char8_t* src, std::wstring& dst) {
CONVFCT_TYPE2(UTF8ToWchar, yycc_char8_t, wchar_t);
}
std::wstring UTF8ToWchar(const yycc_u8string_view& src) {
CONVFCT_TYPE3(UTF8ToWchar, yycc_char8_t, wchar_t);
}
std::wstring UTF8ToWchar(const yycc_char8_t* src) {
CONVFCT_TYPE4(UTF8ToWchar, yycc_char8_t, wchar_t);
}
#pragma endregion
#pragma region CharToUTF8
bool CharToUTF8(const std::string_view& src, yycc_u8string& dst, UINT code_page) {
std::string adapted_dst;
bool ret = CharToChar(src, adapted_dst, code_page, CP_UTF8);
if (ret) dst = ToUTF8(adapted_dst);
return ret;
}
bool CharToUTF8(const char* src, yycc_u8string& dst, UINT code_page) {
CONVFCT_TYPE2(CharToUTF8, char, yycc_char8_t, code_page);
}
yycc_u8string CharToUTF8(const std::string_view& src, UINT code_page) {
CONVFCT_TYPE3(CharToUTF8, char, yycc_char8_t, code_page);
}
yycc_u8string CharToUTF8(const char* src, UINT code_page) {
CONVFCT_TYPE4(CharToUTF8, char, yycc_char8_t, code_page);
}
#pragma endregion
#pragma region UTF8ToChar
bool UTF8ToChar(const yycc_u8string_view& src, std::string& dst, UINT code_page) {
std::string_view adapted_src(ToOrdinaryView(src));
return CharToChar(adapted_src, dst, CP_UTF8, code_page);
}
bool UTF8ToChar(const yycc_char8_t* src, std::string& dst, UINT code_page) {
CONVFCT_TYPE2(UTF8ToChar, yycc_char8_t, char, code_page);
}
std::string UTF8ToChar(const yycc_u8string_view& src, UINT code_page) {
CONVFCT_TYPE3(UTF8ToChar, yycc_char8_t, char, code_page);
}
std::string UTF8ToChar(const yycc_char8_t* src, UINT code_page) {
CONVFCT_TYPE4(UTF8ToChar, yycc_char8_t, char, code_page);
}
#pragma endregion
#endif
#undef CONVFCT_TYPE2
#undef CONVFCT_TYPE3
#undef CONVFCT_TYPE4
}

View File

@ -1,60 +0,0 @@
#pragma once
#include "YYCCInternal.hpp"
#include <string>
#if YYCC_OS == YYCC_OS_WINDOWS
#include "WinImportPrefix.hpp"
#include <Windows.h>
#include "WinImportSuffix.hpp"
#endif
/**
* @brief The helper for all encoding stuff.
* @details
* For more infomations about how to use the functions provided by this namespace,
* please see \ref library_encoding and \ref encoding_helper.
*/
namespace YYCC::EncodingHelper {
#if YYCC_OS == YYCC_OS_WINDOWS
bool WcharToChar(const std::wstring_view& src, std::string& dst, UINT code_page);
bool WcharToChar(const wchar_t* src, std::string& dst, UINT code_page);
std::string WcharToChar(const std::wstring_view& src, UINT code_page);
std::string WcharToChar(const wchar_t* src, UINT code_page);
bool CharToWchar(const std::string_view& src, std::wstring& dst, UINT code_page);
bool CharToWchar(const char* src, std::wstring& dst, UINT code_page);
std::wstring CharToWchar(const std::string_view& src, UINT code_page);
std::wstring CharToWchar(const char* src, UINT code_page);
bool CharToChar(const std::string_view& src, std::string& dst, UINT src_code_page, UINT dst_code_page);
bool CharToChar(const char* src, std::string& dst, UINT src_code_page, UINT dst_code_page);
std::string CharToChar(const std::string_view& src, UINT src_code_page, UINT dst_code_page);
std::string CharToChar(const char* src, UINT src_code_page, UINT dst_code_page);
bool WcharToUTF8(const std::wstring_view& src, yycc_u8string& dst);
bool WcharToUTF8(const wchar_t* src, yycc_u8string& dst);
yycc_u8string WcharToUTF8(const std::wstring_view& src);
yycc_u8string WcharToUTF8(const wchar_t* src);
bool UTF8ToWchar(const yycc_u8string_view& src, std::wstring& dst);
bool UTF8ToWchar(const yycc_char8_t* src, std::wstring& dst);
std::wstring UTF8ToWchar(const yycc_u8string_view& src);
std::wstring UTF8ToWchar(const yycc_char8_t* src);
bool CharToUTF8(const std::string_view& src, yycc_u8string& dst, UINT code_page);
bool CharToUTF8(const char* src, yycc_u8string& dst, UINT code_page);
yycc_u8string CharToUTF8(const std::string_view& src, UINT code_page);
yycc_u8string CharToUTF8(const char* src, UINT code_page);
bool UTF8ToChar(const yycc_u8string_view& src, std::string& dst, UINT code_page);
bool UTF8ToChar(const yycc_char8_t* src, std::string& dst, UINT code_page);
std::string UTF8ToChar(const yycc_u8string_view& src, UINT code_page);
std::string UTF8ToChar(const yycc_char8_t* src, UINT code_page);
#endif
}

View File

@ -1,5 +1,5 @@
#include "ExceptionHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "WinFctHelper.hpp"
#include "ConsoleHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once
#include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
/**
* @brief Windows specific unhandled exception processor.

View File

@ -7,7 +7,7 @@
#include <stdexcept>
#include <memory>
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp"
#include <Windows.h>
#include "WinImportSuffix.hpp"
@ -16,7 +16,7 @@
namespace YYCC::IOHelper {
std::FILE* UTF8FOpen(const yycc_char8_t* u8_filepath, const yycc_char8_t* u8_mode) {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
// convert mode and file path to wchar
std::wstring wmode, wpath;

View File

@ -1,5 +1,5 @@
#include "WinFctHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include "EncodingHelper.hpp"
#include "COMHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once
#include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#include <string>

View File

@ -50,7 +50,7 @@
// If we are in Windows,
// we need add 2 macros to disable Windows shitty warnings and errors of
// depracted functions and not secure functions.
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS

View File

@ -4,11 +4,13 @@
#include "yycc/version.hpp"
#include "yycc/macro/version_cmp.hpp"
// Operating System Identifier Macros
// Detect essential macros
// Operating System macros
#include "yycc/macro/os_detector.hpp"
// Windows Shitty Behavior Disable Macros
#include "yycc/windows/unsafe_suppressor.hpp"
// Compiler macros
#include "yycc/macro/compiler_detector.hpp"
// Endian macros
#include "yycc/macro/endian_detector.hpp"
// Batch Class Move / Copy Function Macros
#include "yycc/macro/class_copy_move.hpp"

View File

@ -1,10 +1,7 @@
#pragma once
#include "../constraint.hpp"
#include "../string.hpp"
#include <set>
#define NS_YYCC_STRING ::yycc::string
/// @brief The namespace containing convenient function building common used Constraint instance.
namespace yycc::constraint::builder {
@ -15,18 +12,12 @@ namespace yycc::constraint::builder {
* @param[in] max_value The maximum value of range (inclusive).
* @return The generated constraint instance which can be directly applied.
*/
template<typename T,
std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, int> = 0>
template<typename T, std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, int> = 0>
Constraint<T> min_max_constraint(T min_value, T max_value) {
if (min_value > max_value)
throw std::invalid_argument("the max value must be equal or greater than min value");
if (min_value > max_value) throw std::invalid_argument("the max value must be equal or greater than min value");
auto fn_check = [min_value, max_value](const T& val) -> bool {
return (val <= max_value) && (val >= min_value);
};
auto fn_clamp = [min_value, max_value](const T& val) -> T {
return std::clamp(val, min_value, max_value);
};
auto fn_check = [min_value, max_value](const T& val) -> bool { return (val <= max_value) && (val >= min_value); };
auto fn_clamp = [min_value, max_value](const T& val) -> T { return std::clamp(val, min_value, max_value); };
return Constraint<T>(std::move(fn_check), std::move(fn_clamp));
}
@ -39,16 +30,13 @@ namespace yycc::constraint::builder {
*/
template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
Constraint<T> enum_constraint(const std::initializer_list<T>& il, size_t default_index = 0u) {
if (default_index >= il.size())
throw std::invalid_argument("the default index must be a valid index in given list");
if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list");
T default_entry = il.begin()[default_index];
std::set<T> entries(il);
// TODO: modify it as `contain` once we finish patch namespace.
auto fn_check = [entries](const T& val) -> bool {
return entries.find(val) != entries.end();
};
auto fn_check = [entries](const T& val) -> bool { return entries.find(val) != entries.end(); };
auto fn_clamp = [entries, default_entry](const T& val) -> T {
if (entries.find(val) != entries.end()) {
return val;
@ -65,30 +53,21 @@ namespace yycc::constraint::builder {
* @param[in] default_index The index of default value in given list.
* @return The generated constraint instance which can be directly applied.
*/
inline Constraint<NS_YYCC_STRING::u8string> strenum_constraint(
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il, size_t default_index = 0u) {
if (default_index >= il.size())
throw std::invalid_argument("the default index must be a valid index in given list");
inline Constraint<std::u8string> strenum_constraint(const std::initializer_list<std::u8string_view>& il, size_t default_index = 0u) {
if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list");
NS_YYCC_STRING::u8string default_entry = NS_YYCC_STRING::u8string(il.begin()[default_index]);
std::set<NS_YYCC_STRING::u8string> entries;
std::u8string default_entry = std::u8string(il.begin()[default_index]);
std::set<std::u8string> entries;
for (const auto& i : il) {
entries.emplace(i);
}
// TODO: modify it as `contain` once we finish patch namespace.
auto fn_check = [entries](const NS_YYCC_STRING::u8string& val) -> bool {
return entries.find(val) != entries.end();
auto fn_check = [entries](const std::u8string& val) -> bool { return entries.contains(val); };
auto fn_clamp = [entries, default_entry](const std::u8string& val) -> std::u8string {
if (entries.contains(val)) return val;
else return default_entry;
};
auto fn_clamp = [entries, default_entry](
const NS_YYCC_STRING::u8string& val) -> NS_YYCC_STRING::u8string {
if (entries.find(val) != entries.end()) {
return val;
} else {
return default_entry;
}
};
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), fn_clamp);
return Constraint<std::u8string>(std::move(fn_check), fn_clamp);
}
} // namespace yycc::constraint::builder

View File

@ -0,0 +1,410 @@
#include "iconv.hpp"
#if YYCC_FEAT_ICONV || !defined(YYCC_OS_WINDOWS)
#include "../string/reinterpret.hpp"
#include "../macro/endian_detector.hpp"
#include <cerrno>
#include <stdexcept>
#include <cstdint>
#include <cstdlib>
#include <vector>
#include <iconv.h>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
#pragma region Iconv Shit Fix
// YYC MARK:
// I don't know what Iconv is for, Iconv put an huge pieces of shit into its header file "iconv.h" (at least for me).
// Especially a macro called iconv, which pollutes my namespace name while also can not be disabled because I need to rely on it to access essential functions.
// I can't simply redefine it, because I can't make sure that this "iconv" is defined in that way on all platforms.
// So I can only write some definitions of functions and types here, and extract the functions and types I need before I declare the namespace.
// And at the same time remove those annoying macro definitions. Hopefully, the compiler will optimize these wrapper functions.
typedef iconv_t that_iconv_t;
static iconv_t that_iconv_open(const char* tocode, const char* fromcode) {
return iconv_open(tocode, fromcode);
}
static int that_iconv_close(iconv_t cd) {
return iconv_close(cd);
}
static size_t that_iconv(iconv_t cd, const char** inbuf, size_t* inbytesleft, char** outbuf, size_t* outbytesleft) {
// YYC MARK:
// This is also bullshit. I don't know why the real signature of this function differ with its document written by GNU.
// I have to make a "const" cast in there.
return iconv(cd, const_cast<char**>(inbuf), inbytesleft, outbuf, outbytesleft);
}
#undef iconv_t
#undef iconv_open
#undef iconv_close
#undef iconv
#pragma endregion
namespace yycc::encoding::iconv {
static const that_iconv_t INVALID_ICONV_TOKEN = reinterpret_cast<that_iconv_t>(-1);
#pragma region PrivToken
class PrivToken {
public:
PrivToken(const CodeName& from_code, const CodeName& to_code) : inner(INVALID_ICONV_TOKEN) {
// We must cast them into string container, not string view,
// because they may not have NULL terminator.
std::string iconv_from_code = NS_YYCC_STRING_REINTERPRET::as_ordinary(from_code),
iconv_to_code = NS_YYCC_STRING_REINTERPRET::as_ordinary(to_code);
// Call iconv_t creator
that_iconv_t descriptor = that_iconv_open(iconv_to_code.c_str(), iconv_from_code.c_str());
if (descriptor == INVALID_ICONV_TOKEN) {
if (errno == EINVAL) {
return;
} else {
throw std::runtime_error("impossible errno when calling iconv_open()");
}
}
// Setup value
this->inner = descriptor;
}
~PrivToken() {
if (this->inner != INVALID_ICONV_TOKEN) {
that_iconv_close(this->inner);
}
}
PrivToken(PrivToken&& rhs) : inner(rhs.inner) {
// Reset rhs inner
rhs.inner = INVALID_ICONV_TOKEN;
}
PrivToken& operator=(PrivToken&& rhs) {
// Free self first
if (this->inner != INVALID_ICONV_TOKEN) {
that_iconv_close(this->inner);
}
// Copy rhs inner and reset it.
this->inner = rhs.inner;
rhs.inner = INVALID_ICONV_TOKEN;
// Return self
return *this;
}
YYCC_DELETE_COPY(PrivToken)
bool is_valid() const { return this->inner != INVALID_ICONV_TOKEN; }
that_iconv_t get_inner() const { return this->inner; }
private:
that_iconv_t inner;
};
#pragma endregion
#pragma region Token
Token::Token(const CodeName& from_code, const CodeName& to_code) : inner(std::make_unique<PrivToken>(from_code, to_code)) {}
Token::~Token() {}
bool Token::is_valid() const {
return this->inner->is_valid();
}
PrivToken* Token::get_inner() const {
return this->inner.get();
}
#pragma endregion
#pragma region Kernel
constexpr const size_t ICONV_INC_LEN = 16u;
constexpr size_t ICONV_ERR_RV = static_cast<size_t>(-1);
// Reference: https://stackoverflow.com/questions/13297458/simple-utf8-utf16-string-conversion-with-iconv
static ConvResult<std::vector<uint8_t>> iconv_kernel(const Token& token, const uint8_t* str_from_buf, size_t str_from_len) {
// ===== Check Requirements =====
// Prepare return value
std::vector<uint8_t> str_to;
// Unwrap and check iconv_t
that_iconv_t cd = token.get_inner()->get_inner();
if (cd == INVALID_ICONV_TOKEN) return ConvError::InvalidCd;
// Check empty input
if (str_from_len == 0u) return str_to;
// Check nullptr input variables
if (str_from_buf == nullptr) return ConvError::NullPointer;
// ===== Do Iconv =====
// setup input variables
size_t inbytesleft = str_from_len;
const char* inbuf = reinterpret_cast<const char*>(str_from_buf);
// pre-allocation output variables
str_to.resize(str_from_len + ICONV_INC_LEN);
size_t outbytesleft = str_to.size();
char* outbuf = reinterpret_cast<char*>(str_to.data());
// conv core
size_t nchars = that_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
while (nchars == ICONV_ERR_RV && errno == E2BIG) {
// record the length has been converted
size_t len = outbuf - reinterpret_cast<char*>(str_to.data());
// resize for container and its variables
str_to.resize(str_to.size() + ICONV_INC_LEN);
outbytesleft = str_to.size();
// assign new outbuf from failed position
outbuf = reinterpret_cast<char*>(str_to.data()) + len;
nchars = that_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
}
// restore descriptor initial state
that_iconv(cd, nullptr, nullptr, nullptr, nullptr);
// check error
if (nchars == ICONV_ERR_RV) {
if (errno == EILSEQ) {
return ConvError::InvalidMbSeq;
} else if (errno == EINVAL) {
return ConvError::IncompleteMbSeq;
} else {
throw std::runtime_error("impossible errno when calling iconv_open()");
}
} else {
// success
// compute result data
str_to.resize(str_to.size() - outbytesleft);
return str_to;
}
}
#pragma endregion
#pragma region Convertion Class Helper
// YYC MARK:
// If we use UTF16 or UTF32 code name directly, it will produce a BOM at data head.
// That's not what we expected.
// So we need manually check runtime endian and explicitly specify endian in code name.
static const NS_YYCC_STRING::u8char* UTF8_CODENAME_LITERAL = YYCC_U8("UTF-8");
static const NS_YYCC_STRING::u8char* WCHAR_CODENAME_LITERAL = YYCC_U8("WCHAR_T");
static const NS_YYCC_STRING::u8char* fetch_utf16_codename() {
#if defined(YYCC_ENDIAN_LITTLE)
return YYCC_U8("UTF16LE");
#else
return YYCC_U8("UTF16BE");
#endif
}
static const NS_YYCC_STRING::u8char* UTF16_CODENAME_LITERAL = fetch_utf16_codename();
static const NS_YYCC_STRING::u8char* fetch_utf32_codename() {
#if defined(YYCC_ENDIAN_LITTLE)
return YYCC_U8("UTF32LE");
#else
return YYCC_U8("UTF32BE");
#endif
}
static const NS_YYCC_STRING::u8char* UTF32_CODENAME_LITERAL = fetch_utf32_codename();
// TODO:
// There is a memory copy in this function. Consider optimizing it in future.
// A possible solution is that create a std::vector-like wrapper for std::basic_string and std::basic_string_view.
// We call them VecString and VecStringView, and use them in "iconv_kernel" instead of real std::vector.
// They exposed interface are std::vector-like but its inner is std::basic_string and std::basic_string_view.
#define CONVFN_TYPE0(src_char_type, dst_char_type) \
namespace expected = NS_YYCC_PATCH_EXPECTED; \
auto rv = iconv_kernel(this->token, reinterpret_cast<const uint8_t*>(src.data()), src.size()); \
if (expected::is_value(rv)) { \
const auto& dst = expected::get_value(rv); \
if constexpr (sizeof(dst_char_type) > 1u) { \
if (dst.size() % sizeof(dst_char_type) != 0u) return ConvError::BadRv; \
} \
return std::basic_string<dst_char_type>(reinterpret_cast<const dst_char_type*>(dst.data()), dst.size() / sizeof(dst_char_type)); \
} else { \
return expected::get_error(rv); \
}
#define CONVFN_TYPE1(fct_name, src_char_type, dst_char_type) \
namespace expected = NS_YYCC_PATCH_EXPECTED; \
auto rv = this->priv_##fct_name(src); \
if (expected::is_value(rv)) { \
dst = std::move(expected::get_value(rv)); \
return true; \
} else { \
return false; \
}
#define CONVFN_TYPE2(fct_name, src_char_type, dst_char_type) \
std::basic_string<dst_char_type> rv; \
if (this->fct_name(src, rv)) return rv; \
else throw std::runtime_error("fail to convert string in Win32 function");
#pragma endregion
#pragma region Char -> UTF8
CharToUtf8::CharToUtf8(const CodeName& code_name) : token(code_name, UTF8_CODENAME_LITERAL) {}
CharToUtf8::~CharToUtf8() {}
ConvResult<NS_YYCC_STRING::u8string> CharToUtf8::priv_to_utf8(const std::string_view& src) {
CONVFN_TYPE0(char, NS_YYCC_STRING::u8char);
}
bool CharToUtf8::to_utf8(const std::string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string CharToUtf8::to_utf8(const std::string_view& src) {
CONVFN_TYPE2(to_utf8, char, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> Char
Utf8ToChar::Utf8ToChar(const CodeName& code_name) : token(UTF8_CODENAME_LITERAL, code_name) {}
Utf8ToChar::~Utf8ToChar() {}
ConvResult<std::string> Utf8ToChar::priv_to_char(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE0(NS_YYCC_STRING::u8char, char);
}
bool Utf8ToChar::to_char(const NS_YYCC_STRING::u8string_view& src, std::string& dst) {
CONVFN_TYPE1(to_char, NS_YYCC_STRING::u8char, char);
}
std::string Utf8ToChar::to_char(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_char, NS_YYCC_STRING::u8char, char);
}
#pragma endregion
#pragma region WChar -> Char
WcharToUtf8::WcharToUtf8() : token(WCHAR_CODENAME_LITERAL, UTF8_CODENAME_LITERAL) {}
WcharToUtf8::~WcharToUtf8() {}
ConvResult<NS_YYCC_STRING::u8string> WcharToUtf8::priv_to_utf8(const std::wstring_view& src) {
CONVFN_TYPE0(wchar_t, NS_YYCC_STRING::u8char);
}
bool WcharToUtf8::to_utf8(const std::wstring_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, wchar_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string WcharToUtf8::to_utf8(const std::wstring_view& src) {
CONVFN_TYPE2(to_utf8, wchar_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region Char -> WChar
Utf8ToWchar::Utf8ToWchar() : token(UTF8_CODENAME_LITERAL, WCHAR_CODENAME_LITERAL) {}
Utf8ToWchar::~Utf8ToWchar() {}
ConvResult<std::wstring> Utf8ToWchar::priv_to_wchar(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE0(NS_YYCC_STRING::u8char, wchar_t);
}
bool Utf8ToWchar::to_wchar(const NS_YYCC_STRING::u8string_view& src, std::wstring& dst) {
CONVFN_TYPE1(to_wchar, NS_YYCC_STRING::u8char, wchar_t);
}
std::wstring Utf8ToWchar::to_wchar(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_wchar, NS_YYCC_STRING::u8char, wchar_t);
}
#pragma endregion
#pragma region UTF8 -> UTF16
Utf8ToUtf16::Utf8ToUtf16() : token(UTF8_CODENAME_LITERAL, UTF16_CODENAME_LITERAL) {}
Utf8ToUtf16::~Utf8ToUtf16() {}
ConvResult<std::u16string> Utf8ToUtf16::priv_to_utf16(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE0(NS_YYCC_STRING::u8char, char16_t);
}
bool Utf8ToUtf16::to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst) {
CONVFN_TYPE1(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
std::u16string Utf8ToUtf16::to_utf16(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
#pragma endregion
#pragma region UTF16 -> UTF8
Utf16ToUtf8::Utf16ToUtf8() : token(UTF16_CODENAME_LITERAL, UTF8_CODENAME_LITERAL) {}
Utf16ToUtf8::~Utf16ToUtf8() {}
ConvResult<NS_YYCC_STRING::u8string> Utf16ToUtf8::priv_to_utf8(const std::u16string_view& src) {
CONVFN_TYPE0(char16_t, NS_YYCC_STRING::u8char);
}
bool Utf16ToUtf8::to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string Utf16ToUtf8::to_utf8(const std::u16string_view& src) {
CONVFN_TYPE2(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> UTF32
Utf8ToUtf32::Utf8ToUtf32() : token(UTF8_CODENAME_LITERAL, UTF32_CODENAME_LITERAL) {}
Utf8ToUtf32::~Utf8ToUtf32() {}
ConvResult<std::u32string> Utf8ToUtf32::priv_to_utf32(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE0(NS_YYCC_STRING::u8char, char32_t);
}
bool Utf8ToUtf32::to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst) {
CONVFN_TYPE1(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
std::u32string Utf8ToUtf32::to_utf32(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
#pragma endregion
#pragma region UTF32 -> UTF8
Utf32ToUtf8::Utf32ToUtf8() : token(UTF32_CODENAME_LITERAL, UTF8_CODENAME_LITERAL) {}
Utf32ToUtf8::~Utf32ToUtf8() {}
ConvResult<NS_YYCC_STRING::u8string> Utf32ToUtf8::priv_to_utf8(const std::u32string_view& src) {
CONVFN_TYPE0(char32_t, NS_YYCC_STRING::u8char);
}
bool Utf32ToUtf8::to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string Utf32ToUtf8::to_utf8(const std::u32string_view& src) {
CONVFN_TYPE2(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
} // namespace yycc::encoding::iconv
#endif

View File

@ -0,0 +1,195 @@
#pragma once
#include "../macro/os_detector.hpp"
#if YYCC_FEAT_ICONV || !defined(YYCC_OS_WINDOWS)
#include "../macro/class_copy_move.hpp"
#include "../patch/expected.hpp"
#include "../string.hpp"
#include <memory>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::iconv {
// YYC MARK:
// I don't want to include "iconv.h" in there.
// One of reasons is that I want to hide all implementation of Iconv.
// Another reason is that "iconv.h" defines some annoying macros which intervene some names in this files.
// So I introduce PIMPL design mode. Use a pointer to hide all details in class PrivToken.
using CodeName = NS_YYCC_STRING::u8string_view;
/// @private
class PrivToken;
class Token {
public:
Token(const CodeName& from_code, const CodeName& to_code);
~Token();
YYCC_DELETE_COPY(Token)
YYCC_DEFAULT_MOVE(Token)
bool is_valid() const;
PrivToken* get_inner() const;
private:
std::unique_ptr<PrivToken> inner;
};
/// @private
enum class ConvError {
InvalidCd, ///< Given token is invalid.
NullPointer, ///< Some of essential pointer in argument is nullptr.
InvalidMbSeq, ///< An invalid multibyte sequence has been encountered in the input.
IncompleteMbSeq, ///< An incomplete multibyte sequence has been encountered in the input.
BadRv, ///< The size of encoding convertion is not matched with expected char type.
};
/// @private
template<typename T>
using ConvResult = NS_YYCC_PATCH_EXPECTED::Expected<T, ConvError>;
// Char -> UTF8
class CharToUtf8 {
public:
CharToUtf8(const CodeName& code_name);
~CharToUtf8();
YYCC_DELETE_COPY(CharToUtf8)
YYCC_DEFAULT_MOVE(CharToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::string_view& src);
bool to_utf8(const std::string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::string_view& src);
private:
Token token;
};
// UTF8 -> Char
class Utf8ToChar {
public:
Utf8ToChar(const CodeName& code_name);
~Utf8ToChar();
YYCC_DELETE_COPY(Utf8ToChar)
YYCC_DEFAULT_MOVE(Utf8ToChar)
public:
ConvResult<std::string> priv_to_char(const NS_YYCC_STRING::u8string_view& src);
bool to_char(const NS_YYCC_STRING::u8string_view& src, std::string& dst);
std::string to_char(const NS_YYCC_STRING::u8string_view& src);
private:
Token token;
};
// WChar -> UTF8
class WcharToUtf8 {
public:
WcharToUtf8();
~WcharToUtf8();
YYCC_DELETE_COPY(WcharToUtf8)
YYCC_DEFAULT_MOVE(WcharToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::wstring_view& src);
bool to_utf8(const std::wstring_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::wstring_view& src);
private:
Token token;
};
// UTF8 -> WChar
class Utf8ToWchar {
public:
Utf8ToWchar();
~Utf8ToWchar();
YYCC_DELETE_COPY(Utf8ToWchar)
YYCC_DEFAULT_MOVE(Utf8ToWchar)
public:
ConvResult<std::wstring> priv_to_wchar(const NS_YYCC_STRING::u8string_view& src);
bool to_wchar(const NS_YYCC_STRING::u8string_view& src, std::wstring& dst);
std::wstring to_wchar(const NS_YYCC_STRING::u8string_view& src);
private:
Token token;
};
// UTF8 -> UTF16
class Utf8ToUtf16 {
public:
Utf8ToUtf16();
~Utf8ToUtf16();
YYCC_DELETE_COPY(Utf8ToUtf16)
YYCC_DEFAULT_MOVE(Utf8ToUtf16)
public:
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src);
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst);
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src);
private:
Token token;
};
// UTF16 -> UTF8
class Utf16ToUtf8 {
public:
Utf16ToUtf8();
~Utf16ToUtf8();
YYCC_DELETE_COPY(Utf16ToUtf8)
YYCC_DEFAULT_MOVE(Utf16ToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src);
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src);
private:
Token token;
};
// UTF8 -> UTF32
class Utf8ToUtf32 {
public:
Utf8ToUtf32();
~Utf8ToUtf32();
YYCC_DELETE_COPY(Utf8ToUtf32)
YYCC_DEFAULT_MOVE(Utf8ToUtf32)
public:
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src);
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst);
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src);
private:
Token token;
};
// UTF32 -> UTF8
class Utf32ToUtf8 {
public:
Utf32ToUtf8();
~Utf32ToUtf8();
YYCC_DELETE_COPY(Utf32ToUtf8)
YYCC_DEFAULT_MOVE(Utf32ToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src);
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src);
private:
Token token;
};
} // namespace yycc::encoding::iconv
#undef NS_YYCC_PATCH_EXPECTED
#undef NS_YYCC_STRING
#endif

View File

@ -0,0 +1,446 @@
#include "pycodec.hpp"
#include <map>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::pycodec {
#pragma region Encoding Name
static const std::map<NS_YYCC_STRING::u8string, NS_YYCC_STRING::u8string> ALISA_MAP {
{ YYCC_U8("646"), YYCC_U8("ascii") },
{ YYCC_U8("us-ascii"), YYCC_U8("ascii") },
{ YYCC_U8("big5-tw"), YYCC_U8("big5") },
{ YYCC_U8("csbig5"), YYCC_U8("big5") },
{ YYCC_U8("big5-hkscs"), YYCC_U8("big5hkscs") },
{ YYCC_U8("hkscs"), YYCC_U8("big5hkscs") },
{ YYCC_U8("ibm037"), YYCC_U8("cp037") },
{ YYCC_U8("ibm039"), YYCC_U8("cp037") },
{ YYCC_U8("273"), YYCC_U8("cp273") },
{ YYCC_U8("ibm273"), YYCC_U8("cp273") },
{ YYCC_U8("csibm273"), YYCC_U8("cp273") },
{ YYCC_U8("ebcdic-cp-he"), YYCC_U8("cp424") },
{ YYCC_U8("ibm424"), YYCC_U8("cp424") },
{ YYCC_U8("437"), YYCC_U8("cp437") },
{ YYCC_U8("ibm437"), YYCC_U8("cp437") },
{ YYCC_U8("ebcdic-cp-be"), YYCC_U8("cp500") },
{ YYCC_U8("ebcdic-cp-ch"), YYCC_U8("cp500") },
{ YYCC_U8("ibm500"), YYCC_U8("cp500") },
{ YYCC_U8("ibm775"), YYCC_U8("cp775") },
{ YYCC_U8("850"), YYCC_U8("cp850") },
{ YYCC_U8("ibm850"), YYCC_U8("cp850") },
{ YYCC_U8("852"), YYCC_U8("cp852") },
{ YYCC_U8("ibm852"), YYCC_U8("cp852") },
{ YYCC_U8("855"), YYCC_U8("cp855") },
{ YYCC_U8("ibm855"), YYCC_U8("cp855") },
{ YYCC_U8("857"), YYCC_U8("cp857") },
{ YYCC_U8("ibm857"), YYCC_U8("cp857") },
{ YYCC_U8("858"), YYCC_U8("cp858") },
{ YYCC_U8("ibm858"), YYCC_U8("cp858") },
{ YYCC_U8("860"), YYCC_U8("cp860") },
{ YYCC_U8("ibm860"), YYCC_U8("cp860") },
{ YYCC_U8("861"), YYCC_U8("cp861") },
{ YYCC_U8("cp-is"), YYCC_U8("cp861") },
{ YYCC_U8("ibm861"), YYCC_U8("cp861") },
{ YYCC_U8("862"), YYCC_U8("cp862") },
{ YYCC_U8("ibm862"), YYCC_U8("cp862") },
{ YYCC_U8("863"), YYCC_U8("cp863") },
{ YYCC_U8("ibm863"), YYCC_U8("cp863") },
{ YYCC_U8("ibm864"), YYCC_U8("cp864") },
{ YYCC_U8("865"), YYCC_U8("cp865") },
{ YYCC_U8("ibm865"), YYCC_U8("cp865") },
{ YYCC_U8("866"), YYCC_U8("cp866") },
{ YYCC_U8("ibm866"), YYCC_U8("cp866") },
{ YYCC_U8("869"), YYCC_U8("cp869") },
{ YYCC_U8("cp-gr"), YYCC_U8("cp869") },
{ YYCC_U8("ibm869"), YYCC_U8("cp869") },
{ YYCC_U8("932"), YYCC_U8("cp932") },
{ YYCC_U8("ms932"), YYCC_U8("cp932") },
{ YYCC_U8("mskanji"), YYCC_U8("cp932") },
{ YYCC_U8("ms-kanji"), YYCC_U8("cp932") },
{ YYCC_U8("windows-31j"), YYCC_U8("cp932") },
{ YYCC_U8("949"), YYCC_U8("cp949") },
{ YYCC_U8("ms949"), YYCC_U8("cp949") },
{ YYCC_U8("uhc"), YYCC_U8("cp949") },
{ YYCC_U8("950"), YYCC_U8("cp950") },
{ YYCC_U8("ms950"), YYCC_U8("cp950") },
{ YYCC_U8("ibm1026"), YYCC_U8("cp1026") },
{ YYCC_U8("1125"), YYCC_U8("cp1125") },
{ YYCC_U8("ibm1125"), YYCC_U8("cp1125") },
{ YYCC_U8("cp866u"), YYCC_U8("cp1125") },
{ YYCC_U8("ruscii"), YYCC_U8("cp1125") },
{ YYCC_U8("ibm1140"), YYCC_U8("cp1140") },
{ YYCC_U8("windows-1250"), YYCC_U8("cp1250") },
{ YYCC_U8("windows-1251"), YYCC_U8("cp1251") },
{ YYCC_U8("windows-1252"), YYCC_U8("cp1252") },
{ YYCC_U8("windows-1253"), YYCC_U8("cp1253") },
{ YYCC_U8("windows-1254"), YYCC_U8("cp1254") },
{ YYCC_U8("windows-1255"), YYCC_U8("cp1255") },
{ YYCC_U8("windows-1256"), YYCC_U8("cp1256") },
{ YYCC_U8("windows-1257"), YYCC_U8("cp1257") },
{ YYCC_U8("windows-1258"), YYCC_U8("cp1258") },
{ YYCC_U8("eucjp"), YYCC_U8("euc_jp") },
{ YYCC_U8("ujis"), YYCC_U8("euc_jp") },
{ YYCC_U8("u-jis"), YYCC_U8("euc_jp") },
{ YYCC_U8("jisx0213"), YYCC_U8("euc_jis_2004") },
{ YYCC_U8("eucjis2004"), YYCC_U8("euc_jis_2004") },
{ YYCC_U8("eucjisx0213"), YYCC_U8("euc_jisx0213") },
{ YYCC_U8("euckr"), YYCC_U8("euc_kr") },
{ YYCC_U8("korean"), YYCC_U8("euc_kr") },
{ YYCC_U8("ksc5601"), YYCC_U8("euc_kr") },
{ YYCC_U8("ks_c-5601"), YYCC_U8("euc_kr") },
{ YYCC_U8("ks_c-5601-1987"), YYCC_U8("euc_kr") },
{ YYCC_U8("ksx1001"), YYCC_U8("euc_kr") },
{ YYCC_U8("ks_x-1001"), YYCC_U8("euc_kr") },
{ YYCC_U8("chinese"), YYCC_U8("gb2312") },
{ YYCC_U8("csiso58gb231280"), YYCC_U8("gb2312") },
{ YYCC_U8("euc-cn"), YYCC_U8("gb2312") },
{ YYCC_U8("euccn"), YYCC_U8("gb2312") },
{ YYCC_U8("eucgb2312-cn"), YYCC_U8("gb2312") },
{ YYCC_U8("gb2312-1980"), YYCC_U8("gb2312") },
{ YYCC_U8("gb2312-80"), YYCC_U8("gb2312") },
{ YYCC_U8("iso-ir-58"), YYCC_U8("gb2312") },
{ YYCC_U8("936"), YYCC_U8("gbk") },
{ YYCC_U8("cp936"), YYCC_U8("gbk") },
{ YYCC_U8("ms936"), YYCC_U8("gbk") },
{ YYCC_U8("gb18030-2000"), YYCC_U8("gb18030") },
{ YYCC_U8("hzgb"), YYCC_U8("hz") },
{ YYCC_U8("hz-gb"), YYCC_U8("hz") },
{ YYCC_U8("hz-gb-2312"), YYCC_U8("hz") },
{ YYCC_U8("csiso2022jp"), YYCC_U8("iso2022_jp") },
{ YYCC_U8("iso2022jp"), YYCC_U8("iso2022_jp") },
{ YYCC_U8("iso-2022-jp"), YYCC_U8("iso2022_jp") },
{ YYCC_U8("iso2022jp-1"), YYCC_U8("iso2022_jp_1") },
{ YYCC_U8("iso-2022-jp-1"), YYCC_U8("iso2022_jp_1") },
{ YYCC_U8("iso2022jp-2"), YYCC_U8("iso2022_jp_2") },
{ YYCC_U8("iso-2022-jp-2"), YYCC_U8("iso2022_jp_2") },
{ YYCC_U8("iso2022jp-2004"), YYCC_U8("iso2022_jp_2004") },
{ YYCC_U8("iso-2022-jp-2004"), YYCC_U8("iso2022_jp_2004") },
{ YYCC_U8("iso2022jp-3"), YYCC_U8("iso2022_jp_3") },
{ YYCC_U8("iso-2022-jp-3"), YYCC_U8("iso2022_jp_3") },
{ YYCC_U8("iso2022jp-ext"), YYCC_U8("iso2022_jp_ext") },
{ YYCC_U8("iso-2022-jp-ext"), YYCC_U8("iso2022_jp_ext") },
{ YYCC_U8("csiso2022kr"), YYCC_U8("iso2022_kr") },
{ YYCC_U8("iso2022kr"), YYCC_U8("iso2022_kr") },
{ YYCC_U8("iso-2022-kr"), YYCC_U8("iso2022_kr") },
{ YYCC_U8("iso-8859-1"), YYCC_U8("latin_1") },
{ YYCC_U8("iso8859-1"), YYCC_U8("latin_1") },
{ YYCC_U8("8859"), YYCC_U8("latin_1") },
{ YYCC_U8("cp819"), YYCC_U8("latin_1") },
{ YYCC_U8("latin"), YYCC_U8("latin_1") },
{ YYCC_U8("latin1"), YYCC_U8("latin_1") },
{ YYCC_U8("l1"), YYCC_U8("latin_1") },
{ YYCC_U8("iso-8859-2"), YYCC_U8("iso8859_2") },
{ YYCC_U8("latin2"), YYCC_U8("iso8859_2") },
{ YYCC_U8("l2"), YYCC_U8("iso8859_2") },
{ YYCC_U8("iso-8859-3"), YYCC_U8("iso8859_3") },
{ YYCC_U8("latin3"), YYCC_U8("iso8859_3") },
{ YYCC_U8("l3"), YYCC_U8("iso8859_3") },
{ YYCC_U8("iso-8859-4"), YYCC_U8("iso8859_4") },
{ YYCC_U8("latin4"), YYCC_U8("iso8859_4") },
{ YYCC_U8("l4"), YYCC_U8("iso8859_4") },
{ YYCC_U8("iso-8859-5"), YYCC_U8("iso8859_5") },
{ YYCC_U8("cyrillic"), YYCC_U8("iso8859_5") },
{ YYCC_U8("iso-8859-6"), YYCC_U8("iso8859_6") },
{ YYCC_U8("arabic"), YYCC_U8("iso8859_6") },
{ YYCC_U8("iso-8859-7"), YYCC_U8("iso8859_7") },
{ YYCC_U8("greek"), YYCC_U8("iso8859_7") },
{ YYCC_U8("greek8"), YYCC_U8("iso8859_7") },
{ YYCC_U8("iso-8859-8"), YYCC_U8("iso8859_8") },
{ YYCC_U8("hebrew"), YYCC_U8("iso8859_8") },
{ YYCC_U8("iso-8859-9"), YYCC_U8("iso8859_9") },
{ YYCC_U8("latin5"), YYCC_U8("iso8859_9") },
{ YYCC_U8("l5"), YYCC_U8("iso8859_9") },
{ YYCC_U8("iso-8859-10"), YYCC_U8("iso8859_10") },
{ YYCC_U8("latin6"), YYCC_U8("iso8859_10") },
{ YYCC_U8("l6"), YYCC_U8("iso8859_10") },
{ YYCC_U8("iso-8859-11"), YYCC_U8("iso8859_11") },
{ YYCC_U8("thai"), YYCC_U8("iso8859_11") },
{ YYCC_U8("iso-8859-13"), YYCC_U8("iso8859_13") },
{ YYCC_U8("latin7"), YYCC_U8("iso8859_13") },
{ YYCC_U8("l7"), YYCC_U8("iso8859_13") },
{ YYCC_U8("iso-8859-14"), YYCC_U8("iso8859_14") },
{ YYCC_U8("latin8"), YYCC_U8("iso8859_14") },
{ YYCC_U8("l8"), YYCC_U8("iso8859_14") },
{ YYCC_U8("iso-8859-15"), YYCC_U8("iso8859_15") },
{ YYCC_U8("latin9"), YYCC_U8("iso8859_15") },
{ YYCC_U8("l9"), YYCC_U8("iso8859_15") },
{ YYCC_U8("iso-8859-16"), YYCC_U8("iso8859_16") },
{ YYCC_U8("latin10"), YYCC_U8("iso8859_16") },
{ YYCC_U8("l10"), YYCC_U8("iso8859_16") },
{ YYCC_U8("cp1361"), YYCC_U8("johab") },
{ YYCC_U8("ms1361"), YYCC_U8("johab") },
{ YYCC_U8("kz_1048"), YYCC_U8("kz1048") },
{ YYCC_U8("strk1048_2002"), YYCC_U8("kz1048") },
{ YYCC_U8("rk1048"), YYCC_U8("kz1048") },
{ YYCC_U8("maccyrillic"), YYCC_U8("mac_cyrillic") },
{ YYCC_U8("macgreek"), YYCC_U8("mac_greek") },
{ YYCC_U8("maciceland"), YYCC_U8("mac_iceland") },
{ YYCC_U8("maclatin2"), YYCC_U8("mac_latin2") },
{ YYCC_U8("maccentraleurope"), YYCC_U8("mac_latin2") },
{ YYCC_U8("mac_centeuro"), YYCC_U8("mac_latin2") },
{ YYCC_U8("macroman"), YYCC_U8("mac_roman") },
{ YYCC_U8("macintosh"), YYCC_U8("mac_roman") },
{ YYCC_U8("macturkish"), YYCC_U8("mac_turkish") },
{ YYCC_U8("csptcp154"), YYCC_U8("ptcp154") },
{ YYCC_U8("pt154"), YYCC_U8("ptcp154") },
{ YYCC_U8("cp154"), YYCC_U8("ptcp154") },
{ YYCC_U8("cyrillic-asian"), YYCC_U8("ptcp154") },
{ YYCC_U8("csshiftjis"), YYCC_U8("shift_jis") },
{ YYCC_U8("shiftjis"), YYCC_U8("shift_jis") },
{ YYCC_U8("sjis"), YYCC_U8("shift_jis") },
{ YYCC_U8("s_jis"), YYCC_U8("shift_jis") },
{ YYCC_U8("shiftjis2004"), YYCC_U8("shift_jis_2004") },
{ YYCC_U8("sjis_2004"), YYCC_U8("shift_jis_2004") },
{ YYCC_U8("sjis2004"), YYCC_U8("shift_jis_2004") },
{ YYCC_U8("shiftjisx0213"), YYCC_U8("shift_jisx0213") },
{ YYCC_U8("sjisx0213"), YYCC_U8("shift_jisx0213") },
{ YYCC_U8("s_jisx0213"), YYCC_U8("shift_jisx0213") },
{ YYCC_U8("u32"), YYCC_U8("utf_32") },
{ YYCC_U8("utf32"), YYCC_U8("utf_32") },
{ YYCC_U8("utf-32be"), YYCC_U8("utf_32_be") },
{ YYCC_U8("utf-32le"), YYCC_U8("utf_32_le") },
{ YYCC_U8("u16"), YYCC_U8("utf_16") },
{ YYCC_U8("utf16"), YYCC_U8("utf_16") },
{ YYCC_U8("utf-16be"), YYCC_U8("utf_16_be") },
{ YYCC_U8("utf-16le"), YYCC_U8("utf_16_le") },
{ YYCC_U8("u7"), YYCC_U8("utf_7") },
{ YYCC_U8("unicode-1-1-utf-7"), YYCC_U8("utf_7") },
{ YYCC_U8("u8"), YYCC_U8("utf_8") },
{ YYCC_U8("utf"), YYCC_U8("utf_8") },
{ YYCC_U8("utf8"), YYCC_U8("utf_8") },
{ YYCC_U8("utf-8"), YYCC_U8("utf_8") },
{ YYCC_U8("cp65001"), YYCC_U8("utf_8") },
};
#if defined(YYCC_PYCODEC_WIN32_BACKEND)
using CodePage = NS_YYCC_ENCODING_BACKEND::CodePage;
static const std::map<NS_YYCC_STRING::u8string, CodePage> WINCP_MAP {
{ YYCC_U8("ascii"), static_cast<CodePage>(437u) },
{ YYCC_U8("big5"), static_cast<CodePage>(950u) },
{ YYCC_U8("cp037"), static_cast<CodePage>(037u) },
{ YYCC_U8("cp437"), static_cast<CodePage>(437u) },
{ YYCC_U8("cp500"), static_cast<CodePage>(500u) },
{ YYCC_U8("cp720"), static_cast<CodePage>(720u) },
{ YYCC_U8("cp737"), static_cast<CodePage>(737u) },
{ YYCC_U8("cp775"), static_cast<CodePage>(775u) },
{ YYCC_U8("cp850"), static_cast<CodePage>(850u) },
{ YYCC_U8("cp852"), static_cast<CodePage>(852u) },
{ YYCC_U8("cp855"), static_cast<CodePage>(855u) },
{ YYCC_U8("cp857"), static_cast<CodePage>(857u) },
{ YYCC_U8("cp858"), static_cast<CodePage>(858u) },
{ YYCC_U8("cp860"), static_cast<CodePage>(860u) },
{ YYCC_U8("cp861"), static_cast<CodePage>(861u) },
{ YYCC_U8("cp862"), static_cast<CodePage>(862u) },
{ YYCC_U8("cp863"), static_cast<CodePage>(863u) },
{ YYCC_U8("cp864"), static_cast<CodePage>(864u) },
{ YYCC_U8("cp865"), static_cast<CodePage>(865u) },
{ YYCC_U8("cp866"), static_cast<CodePage>(866u) },
{ YYCC_U8("cp869"), static_cast<CodePage>(869u) },
{ YYCC_U8("cp874"), static_cast<CodePage>(874u) },
{ YYCC_U8("cp875"), static_cast<CodePage>(875u) },
{ YYCC_U8("cp932"), static_cast<CodePage>(932u) },
{ YYCC_U8("cp949"), static_cast<CodePage>(949u) },
{ YYCC_U8("cp950"), static_cast<CodePage>(950u) },
{ YYCC_U8("cp1026"), static_cast<CodePage>(1026u) },
{ YYCC_U8("cp1140"), static_cast<CodePage>(1140u) },
{ YYCC_U8("cp1250"), static_cast<CodePage>(1250u) },
{ YYCC_U8("cp1251"), static_cast<CodePage>(1251u) },
{ YYCC_U8("cp1252"), static_cast<CodePage>(1252u) },
{ YYCC_U8("cp1253"), static_cast<CodePage>(1253u) },
{ YYCC_U8("cp1254"), static_cast<CodePage>(1254u) },
{ YYCC_U8("cp1255"), static_cast<CodePage>(1255u) },
{ YYCC_U8("cp1256"), static_cast<CodePage>(1256u) },
{ YYCC_U8("cp1257"), static_cast<CodePage>(1257u) },
{ YYCC_U8("cp1258"), static_cast<CodePage>(1258u) },
{ YYCC_U8("euc_jp"), static_cast<CodePage>(20932u) },
{ YYCC_U8("euc_kr"), static_cast<CodePage>(51949u) },
{ YYCC_U8("gb2312"), static_cast<CodePage>(936u) },
{ YYCC_U8("gbk"), static_cast<CodePage>(936u) },
{ YYCC_U8("gb18030"), static_cast<CodePage>(54936u) },
{ YYCC_U8("hz"), static_cast<CodePage>(52936u) },
{ YYCC_U8("iso2022_jp"), static_cast<CodePage>(50220u) },
{ YYCC_U8("iso2022_kr"), static_cast<CodePage>(50225u) },
{ YYCC_U8("latin_1"), static_cast<CodePage>(28591u) },
{ YYCC_U8("iso8859_2"), static_cast<CodePage>(28592u) },
{ YYCC_U8("iso8859_3"), static_cast<CodePage>(28593u) },
{ YYCC_U8("iso8859_4"), static_cast<CodePage>(28594u) },
{ YYCC_U8("iso8859_5"), static_cast<CodePage>(28595u) },
{ YYCC_U8("iso8859_6"), static_cast<CodePage>(28596u) },
{ YYCC_U8("iso8859_7"), static_cast<CodePage>(28597u) },
{ YYCC_U8("iso8859_8"), static_cast<CodePage>(28598u) },
{ YYCC_U8("iso8859_9"), static_cast<CodePage>(28599u) },
{ YYCC_U8("iso8859_13"), static_cast<CodePage>(28603u) },
{ YYCC_U8("iso8859_15"), static_cast<CodePage>(28605u) },
{ YYCC_U8("johab"), static_cast<CodePage>(1361u) },
{ YYCC_U8("mac_cyrillic"), static_cast<CodePage>(10007u) },
{ YYCC_U8("mac_greek"), static_cast<CodePage>(10006u) },
{ YYCC_U8("mac_iceland"), static_cast<CodePage>(10079u) },
{ YYCC_U8("mac_turkish"), static_cast<CodePage>(10081u) },
{ YYCC_U8("shift_jis"), static_cast<CodePage>(932u) },
{ YYCC_U8("utf_7"), static_cast<CodePage>(65000u) },
{ YYCC_U8("utf_8"), static_cast<CodePage>(65001u) },
};
#else
static const std::map<NS_YYCC_STRING::u8string, std::string> ICONV_MAP {
{ YYCC_U8("ascii"), "ASCII" },
{ YYCC_U8("big5"), "BIG5" },
{ YYCC_U8("big5hkscs"), "BIG5-HKSCS" },
{ YYCC_U8("cp850"), "CP850" },
{ YYCC_U8("cp862"), "CP862" },
{ YYCC_U8("cp866"), "CP866" },
{ YYCC_U8("cp874"), "CP874" },
{ YYCC_U8("cp932"), "CP932" },
{ YYCC_U8("cp949"), "CP949" },
{ YYCC_U8("cp950"), "CP950" },
{ YYCC_U8("cp1250"), "CP1250" },
{ YYCC_U8("cp1251"), "CP1251" },
{ YYCC_U8("cp1252"), "CP1252" },
{ YYCC_U8("cp1253"), "CP1253" },
{ YYCC_U8("cp1254"), "CP1254" },
{ YYCC_U8("cp1255"), "CP1255" },
{ YYCC_U8("cp1256"), "CP1256" },
{ YYCC_U8("cp1257"), "CP1257" },
{ YYCC_U8("cp1258"), "CP1258" },
{ YYCC_U8("euc_jp"), "EUC-JP" },
{ YYCC_U8("euc_kr"), "EUC-KR" },
{ YYCC_U8("gb2312"), "CP936" },
{ YYCC_U8("gbk"), "GBK" },
{ YYCC_U8("gb18030"), "GB18030" },
{ YYCC_U8("hz"), "HZ" },
{ YYCC_U8("iso2022_jp"), "ISO-2022-JP" },
{ YYCC_U8("iso2022_jp_1"), "ISO-2022-JP-1" },
{ YYCC_U8("iso2022_jp_2"), "ISO-2022-JP-2" },
{ YYCC_U8("iso2022_kr"), "ISO-2022-KR" },
{ YYCC_U8("latin_1"), "ISO-8859-1" },
{ YYCC_U8("iso8859_2"), "ISO-8859-2" },
{ YYCC_U8("iso8859_3"), "ISO-8859-3" },
{ YYCC_U8("iso8859_4"), "ISO-8859-4" },
{ YYCC_U8("iso8859_5"), "ISO-8859-5" },
{ YYCC_U8("iso8859_6"), "ISO-8859-6" },
{ YYCC_U8("iso8859_7"), "ISO-8859-7" },
{ YYCC_U8("iso8859_8"), "ISO-8859-8" },
{ YYCC_U8("iso8859_9"), "ISO-8859-9" },
{ YYCC_U8("iso8859_10"), "ISO-8859-10" },
{ YYCC_U8("iso8859_11"), "ISO-8859-11" },
{ YYCC_U8("iso8859_13"), "ISO-8859-13" },
{ YYCC_U8("iso8859_14"), "ISO-8859-14" },
{ YYCC_U8("iso8859_15"), "ISO-8859-15" },
{ YYCC_U8("iso8859_16"), "ISO-8859-16" },
{ YYCC_U8("johab"), "JOHAB" },
{ YYCC_U8("koi8_t"), "KOI8-T" },
{ YYCC_U8("mac_cyrillic"), "MacCyrillic" },
{ YYCC_U8("mac_greek"), "MacGreek" },
{ YYCC_U8("mac_iceland"), "MacIceland" },
{ YYCC_U8("mac_roman"), "MacRoman" },
{ YYCC_U8("mac_turkish"), "MacTurkish" },
{ YYCC_U8("ptcp154"), "PT154" },
{ YYCC_U8("shift_jis"), "SHIFT_JIS" },
{ YYCC_U8("utf_32"), "UTF-32" },
{ YYCC_U8("utf_32_be"), "UTF-32BE" },
{ YYCC_U8("utf_32_le"), "UTF-32LE" },
{ YYCC_U8("utf_16"), "UTF16" },
{ YYCC_U8("utf_16_be"), "UTF-16BE" },
{ YYCC_U8("utf_16_le"), "UTF-16LE" },
{ YYCC_U8("utf_7"), "UTF-7" },
{ YYCC_U8("utf_8"), "UTF-8" },
};
#endif
#pragma endregion
#pragma region Misc
ConvError::ConvError(const ConvError::Error& err) : inner(err) {}
bool is_valid_encoding_name(const EncodingName& name) {
}
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
#pragma region
#pragma endregion
} // namespace yycc::encoding::pycodec

View File

@ -0,0 +1,202 @@
#pragma once
#include "../macro/os_detector.hpp"
#include "../macro/class_copy_move.hpp"
#include "../patch/expected.hpp"
#include "../string.hpp"
// Choose the backend of PyCodec module
#if defined(YYCC_OS_WINDOWS)
#include "windows.hpp"
#define YYCC_PYCODEC_WIN32_BACKEND
#define NS_YYCC_ENCODING_BACKEND ::yycc::encoding::windows
#else
#include "iconv.hpp"
#define YYCC_PYCODEC_ICONV_BACKEND
#define NS_YYCC_ENCODING_BACKEND ::yycc::encoding::iconv
#endif
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::pycodec {
using EncodingName = NS_YYCC_STRING::u8string_view;
/// @private
struct ConvError {
using Error = NS_YYCC_ENCODING_BACKEND::ConvError;
ConvError(const Error& err);
Error inner;
};
/// @private
template<typename T>
using ConvResult = NS_YYCC_PATCH_EXPECTED::Expected<T, ConvError>;
/**
* @brief Check whether given name is a valid encoding name in PyCodec.
* @param[in] name The name to be checked.
* @return True if it is valid, otherwise false.
*/
bool is_valid_encoding_name(const EncodingName& name);
// Char -> UTF8
class CharToUtf8 {
public:
CharToUtf8(const EncodingName& name);
~CharToUtf8();
YYCC_DELETE_COPY(CharToUtf8)
YYCC_DEFAULT_MOVE(CharToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::string_view& src);
bool to_utf8(const std::string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::string_view& src);
private:
#if defined(YYCC_PYCODEC_WIN32_BACKEND)
NS_YYCC_ENCODING_BACKEND::CodePage code_page;
#else
NS_YYCC_ENCODING_BACKEND::CharToUtf8 inner;
#endif
};
// UTF8 -> Char
class Utf8ToChar {
public:
Utf8ToChar(const EncodingName& name);
~Utf8ToChar();
YYCC_DELETE_COPY(Utf8ToChar)
YYCC_DEFAULT_MOVE(Utf8ToChar)
public:
ConvResult<std::string> priv_to_char(const NS_YYCC_STRING::u8string_view& src);
bool to_char(const NS_YYCC_STRING::u8string_view& src, std::string& dst);
std::string to_char(const NS_YYCC_STRING::u8string_view& src);
private:
#if defined(YYCC_PYCODEC_WIN32_BACKEND)
NS_YYCC_ENCODING_BACKEND::CodePage code_page;
#else
NS_YYCC_ENCODING_BACKEND::Utf8ToChar inner;
#endif
};
// WChar -> UTF8
class WcharToUtf8 {
public:
WcharToUtf8();
~WcharToUtf8();
YYCC_DELETE_COPY(WcharToUtf8)
YYCC_DEFAULT_MOVE(WcharToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::wstring_view& src);
bool to_utf8(const std::wstring_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::wstring_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::WcharToUtf8 inner;
#endif
};
// UTF8 -> WChar
class Utf8ToWchar {
public:
Utf8ToWchar();
~Utf8ToWchar();
YYCC_DELETE_COPY(Utf8ToWchar)
YYCC_DEFAULT_MOVE(Utf8ToWchar)
public:
ConvResult<std::wstring> priv_to_wchar(const NS_YYCC_STRING::u8string_view& src);
bool to_wchar(const NS_YYCC_STRING::u8string_view& src, std::wstring& dst);
std::wstring to_wchar(const NS_YYCC_STRING::u8string_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::Utf8ToWchar inner;
#endif
};
// UTF8 -> UTF16
class Utf8ToUtf16 {
public:
Utf8ToUtf16();
~Utf8ToUtf16();
YYCC_DELETE_COPY(Utf8ToUtf16)
YYCC_DEFAULT_MOVE(Utf8ToUtf16)
public:
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src);
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst);
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::Utf8ToUtf16 inner;
#endif
};
// UTF16 -> UTF8
class Utf16ToUtf8 {
public:
Utf16ToUtf8();
~Utf16ToUtf8();
YYCC_DELETE_COPY(Utf16ToUtf8)
YYCC_DEFAULT_MOVE(Utf16ToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src);
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::Utf16ToUtf8 inner;
#endif
};
// UTF8 -> UTF32
class Utf8ToUtf32 {
public:
Utf8ToUtf32();
~Utf8ToUtf32();
YYCC_DELETE_COPY(Utf8ToUtf32)
YYCC_DEFAULT_MOVE(Utf8ToUtf32)
public:
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src);
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst);
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::Utf8ToUtf32 inner;
#endif
};
// UTF32 -> UTF8
class Utf32ToUtf8 {
public:
Utf32ToUtf8();
~Utf32ToUtf8();
YYCC_DELETE_COPY(Utf32ToUtf8)
YYCC_DEFAULT_MOVE(Utf32ToUtf8)
public:
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src);
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src);
private:
#if defined(YYCC_PYCODEC_ICONV_BACKEND)
NS_YYCC_ENCODING_BACKEND::Utf32ToUtf8 inner;
#endif
};
}
#undef NS_YYCC_PATCH_EXPECTED
#undef NS_YYCC_STRING

View File

@ -0,0 +1,118 @@
#include "stlcvt.hpp"
#include <locale>
namespace yycc::encoding::stlcvt {
#pragma region Generic Converter
/*
* YYC MARK:
* According to the documentation introduced in CppReference.
* The standard library is guaranteed to provide several specific specializations of \c std::codecvt.
* The UTF8 char type in UTF8 related specializations of \c std::codecvt is different in different C++ standard.
* But the oldest C++ version YYCC supported is C++ 23, char8_t is the only viable UTF8 char type for \c std::codecvt.
* So we can simply and safely use it to correctly trigger specific specializations of \c std::codecv in there.
*/
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
using CodecvtFacet = std::codecvt<TChar, char8_t, std::mbstate_t>;
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
static ConvResult<std::basic_string<TChar>> generic_to_utf_other(const std::u8string_view& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/in
// prepare return value
std::basic_string<TChar> dst;
// if src is empty, return directly
if (src.empty()) {
return dst;
}
// init locale and get codecvt facet
// same reason in UTFOtherToUTF8 to keeping reference to locale
const auto& this_locale = std::locale::classic();
const auto& this_codecvt = std::use_facet<CodecvtFacet<TChar>>(this_locale);
// convertion preparation
std::mbstate_t mb{};
dst.resize(src.size());
const char8_t *intern_from = reinterpret_cast<const char8_t*>(src.data()),
*intern_from_end = reinterpret_cast<const char8_t*>(src.data() + src.size()), *intern_from_next = nullptr;
TChar *extern_to = dst.data(), *extern_to_end = dst.data() + dst.size(), *extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.in(mb, intern_from, intern_from_end, intern_from_next, extern_to, extern_to_end, extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return std::unexpected(ConvError{});
// resize result and return
dst.resize(extern_to_next - dst.data());
return dst;
}
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
static ConvResult<std::u8string> generic_to_utf8(const std::basic_string_view<TChar>& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/out
// prepare return value
std::u8string dst;
// if src is empty, return directly
if (src.empty()) {
return dst;
}
// init locale and get codecvt facet
// the reference to locale must be preserved until convertion done.
// because the life time of codecvt facet is equal to the reference to locale.
const auto& this_locale = std::locale::classic();
const auto& this_codecvt = std::use_facet<CodecvtFacet<TChar>>(this_locale);
// do convertion preparation
std::mbstate_t mb{};
dst.resize(src.size() * this_codecvt.max_length());
const TChar *intern_from = src.data(), *intern_from_end = src.data() + src.size(), *intern_from_next = nullptr;
char8_t *extern_to = reinterpret_cast<char8_t*>(dst.data()), *extern_to_end = reinterpret_cast<char8_t*>(dst.data() + dst.size()),
*extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.out(mb, intern_from, intern_from_end, intern_from_next, extern_to, extern_to_end, extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return std::unexpected(ConvError{});
// resize result and retuen
dst.resize(extern_to_next - reinterpret_cast<char8_t*>(dst.data()));
return dst;
}
#pragma endregion Converter
#pragma region
ConvResult<std::u16string> to_utf16(const std::u8string_view& src) {
// UTF8 -> UTF16
return generic_to_utf_other<char16_t>(src);
}
ConvResult<std::u8string> to_utf8(const std::u16string_view& src) {
// UTF16 -> UTF8
return generic_to_utf8<char16_t>(src);
}
ConvResult<std::u32string> to_utf32(const std::u8string_view& src) {
// UTF8 -> UTF32
return generic_to_utf_other<char32_t>(src);
}
ConvResult<std::u8string> to_utf8(const std::u32string_view& src) {
// UTF32 -> UTF8
return generic_to_utf8<char32_t>(src);
}
#pragma endregion
} // namespace yycc::encoding::stlcvt

View File

@ -0,0 +1,43 @@
#pragma once
#include <string>
#include <string_view>
#include <expected>
namespace yycc::encoding::stlcvt {
/// @brief Possible convertion error occurs in this module.
struct ConvError {};
/// @brief The result type of this module.
template<typename T>
using ConvResult = std::expected<T, ConvError>;
/**
* @brief UTF8 -> UTF16
* @param src
* @return
*/
ConvResult<std::u16string> to_utf16(const std::u8string_view& src);
/**
* @brief UTF16 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u16string_view& src);
/**
* @brief UTF8 -> UTF32
* @param src
* @return
*/
ConvResult<std::u32string> to_utf32(const std::u8string_view& src);
/**
* @brief UTF32 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> utf8(const std::u32string_view& src);
}

View File

@ -1,201 +0,0 @@
#include "utf.hpp"
#include "../macro/feature_probe.hpp"
#include <locale>
#define NS_YYCC_STRING ::yycc::string
namespace yycc::encoding::utf {
#pragma region Generic Converter
/*
* NOTE:
* According to the documentation introduced in CppReference.
* The standard library is guaranteed to provide several specific specializations of \c std::codecvt.
* The UTF8 char type in UTF8 related specializations of \c std::codecvt is different.
* It is also independend from we defined char type.
* So it is essential define a type which can correctly trigger specific specializations of \c std::codecv in there.
*/
#if defined(YYCC_CPPFEAT_UTF8)
using CodecvtUtf8Char = char8_t;
#else
using CodecvtUtf8Char = char;
#endif
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
using CodecvtFacet = std::codecvt<TChar, CodecvtUtf8Char, std::mbstate_t>;
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
static ConvResult<std::basic_string<TChar>> generic_to_utf_other(
const NS_YYCC_STRING::u8string_view& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/in
// prepare return value
std::basic_string<TChar> dst;
// if src is empty, return directly
if (src.empty()) {
return dst;
}
// init locale and get codecvt facet
// same reason in UTFOtherToUTF8 to keeping reference to locale
const auto& this_locale = std::locale::classic();
const auto& this_codecvt = std::use_facet<CodecvtFacet<TChar>>(this_locale);
// convertion preparation
std::mbstate_t mb{};
dst.resize(src.size());
const CodecvtUtf8Char *intern_from = reinterpret_cast<const CodecvtUtf8Char*>(src.data()),
*intern_from_end = reinterpret_cast<const CodecvtUtf8Char*>(
src.data() + src.size()),
*intern_from_next = nullptr;
TChar *extern_to = dst.data(), *extern_to_end = dst.data() + dst.size(),
*extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.in(mb,
intern_from,
intern_from_end,
intern_from_next,
extern_to,
extern_to_end,
extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return ConvError();
// resize result and return
dst.resize(extern_to_next - dst.data());
return dst;
}
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
static ConvResult<NS_YYCC_STRING::u8string> generic_to_utf8(
const std::basic_string_view<TChar>& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/out
// prepare return value
NS_YYCC_STRING::u8string dst;
// if src is empty, return directly
if (src.empty()) {
return dst;
}
// init locale and get codecvt facet
// the reference to locale must be preserved until convertion done.
// because the life time of codecvt facet is equal to the reference to locale.
const auto& this_locale = std::locale::classic();
const auto& this_codecvt = std::use_facet<CodecvtFacet<TChar>>(this_locale);
// do convertion preparation
std::mbstate_t mb{};
dst.resize(src.size() * this_codecvt.max_length());
const TChar *intern_from = src.data(), *intern_from_end = src.data() + src.size(),
*intern_from_next = nullptr;
CodecvtUtf8Char *extern_to = reinterpret_cast<CodecvtUtf8Char*>(dst.data()),
*extern_to_end = reinterpret_cast<CodecvtUtf8Char*>(dst.data() + dst.size()),
*extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.out(mb,
intern_from,
intern_from_end,
intern_from_next,
extern_to,
extern_to_end,
extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return ConvError();
// resize result and retuen
dst.resize(extern_to_next - reinterpret_cast<CodecvtUtf8Char*>(dst.data()));
return dst;
}
#pragma endregion
#pragma region Help Macros
#define CONVFN_TYPE1(fct_name, src_char_type, dst_char_type) \
auto rv = priv_##fct_name(src); \
if (const auto* ptr = std::get_if<std::basic_string<dst_char_type>>(&rv)) { \
dst = std::move(*ptr); \
return true; \
} else if (const auto* ptr = std::get_if<ConvError>(&rv)) { \
return false; \
} else { \
throw std::runtime_error("unreachable code"); \
}
#define CONVFN_TYPE2(fct_name, src_char_type, dst_char_type) \
std::basic_string<dst_char_type> rv; \
if (fct_name(src, rv)) return rv; \
else throw std::runtime_error("fail to convert utf string");
#pragma endregion
#pragma region UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src) {
return generic_to_utf_other<char16_t>(src);
}
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst) {
CONVFN_TYPE1(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
#pragma endregion
#pragma region UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src) {
return generic_to_utf8<char16_t>(src);
}
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src) {
CONVFN_TYPE2(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src) {
return generic_to_utf_other<char32_t>(src);
}
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst) {
CONVFN_TYPE1(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
#pragma endregion
#pragma region UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src) {
return generic_to_utf8<char32_t>(src);
}
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src) {
CONVFN_TYPE2(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
} // namespace yycc::encoding::utf

View File

@ -1,43 +0,0 @@
#pragma once
#include <yycc/string.hpp>
#include <type_traits>
#include <variant>
#define NS_YYCC_STRING ::yycc::string
namespace yycc::encoding::utf {
/// @private
struct ConvError {};
/// @private
template<typename T, std::enable_if_t<!std::is_same_v<T, ConvError>, int> = 0>
using ConvResult = std::variant<T, ConvError>;
// UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src);
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst);
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src);
// UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src);
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src);
// UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src);
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst);
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src);
// UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src);
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src);
}
#undef NS_YYCC_STRING

View File

@ -0,0 +1,213 @@
#include "windows.hpp"
#if defined(YYCC_OS_WINDOWS)
#include "../string/reinterpret.hpp"
#include <limits>
#include <stdexcept>
#include <cuchar>
#include "../windows/import_guard_head.hpp"
#include <Windows.h>
#include "../windows/import_guard_tail.hpp"
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
namespace yycc::encoding::windows {
#pragma region WideCharToMultiByte and MultiByteToWideChar stuff
// WChar -> Char
ConvResult<std::string> to_char(const std::wstring_view& src, CodePage code_page) {
// prepare result
std::string dst;
// if src is empty, direct output
if (src.empty()) {
return dst;
}
// init WideCharToMultiByte used variables
// setup src pointer
LPCWCH lpWideCharStr = reinterpret_cast<LPCWCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return std::unexpected(ConvError::TooLargeLength);
int cchWideChar = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
if (desired_size <= 0) return std::unexpected(ConvError::NoDesiredSize);
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result
= WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, reinterpret_cast<LPSTR>(dst.data()), desired_size, NULL, NULL);
if (write_result <= 0) return std::unexpected(ConvError::BadWrittenSize);
return dst;
}
// Char -> WChar
ConvResult<std::wstring> to_wchar(const std::string_view& src, CodePage code_page) {
// prepare result
std::wstring dst;
// if src is empty, direct output
if (src.empty()) {
return dst;
}
// init WideCharToMultiByte used variables
// setup src pointer
LPCCH lpMultiByteStr = reinterpret_cast<LPCCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return std::unexpected(ConvError::TooLargeLength);
int cbMultiByte = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, NULL, 0);
if (desired_size <= 0) return std::unexpected(ConvError::NoDesiredSize);
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, reinterpret_cast<LPWSTR>(dst.data()), desired_size);
if (write_result <= 0) return std::unexpected(ConvError::BadWrittenSize);
return dst;
}
// Char -> Char
ConvResult<std::string> to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page) {
auto first_rv = to_wchar(src, src_code_page);
return first_rv.and_then([dst_code_page](const auto& src) { return to_char(src, dst_code_page); });
}
// WChar -> UTF8
ConvResult<std::u8string> to_utf8(const std::wstring_view& src) {
auto rv = to_char(src, CP_UTF8);
return rv.transform([](const auto& dst) { return NS_YYCC_STRING_REINTERPRET::as_utf8(dst); });
}
// UTF8 -> WChar
ConvResult<std::wstring> to_wchar(const std::u8string_view& src) {
return to_wchar(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8);
}
// Char -> UTF8
ConvResult<std::u8string> to_utf8(const std::string_view& src, CodePage code_page) {
auto rv = to_char(src, code_page, CP_UTF8);
return rv.transform([](const auto& dst) { return NS_YYCC_STRING_REINTERPRET::as_utf8(dst); });
}
// UTF8 -> Char
ConvResult<std::string> to_char(const std::u8string_view& src, CodePage code_page) {
return to_char(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8, code_page);
}
#pragma endregion
#pragma region UTF stuff
// YYC MARK:
// The convertion between UTF is implemented by c16rtomb, c32rtomb, mbrtoc16 and mbrtoc32.
// These function is locale related in C++ standard, but in Microsoft STL, it's only for UTF8.
// So we can use them safely in Win32 environment.
// Reference:
// * https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/c16rtomb-c32rtomb1?view=msvc-170
// * https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mbrtoc16-mbrtoc323?view=msvc-170
// 1 UTF32 unit can produe 4 UTF8 units or 2 UTF16 units in theory.
// So we pre-allocate memory for the result to prevent allocating memory multiple times.
constexpr size_t MULTIPLE_UTF8_TO_UTF16 = 1u;
constexpr size_t MULTIPLE_UTF16_TO_UTF8 = 2u;
constexpr size_t MULTIPLE_UTF8_TO_UTF32 = 1u;
constexpr size_t MULTIPLE_UTF32_TO_UTF8 = 4u;
// UTF8 -> UTF16
ConvResult<std::u16string> to_utf16(const std::u8string_view& src) {
std::u16string dst;
dst.reserve(src.size() * MULTIPLE_UTF8_TO_UTF16);
std::mbstate_t state{}; // zero-initialized to initial state
char16_t c16;
const char* ptr = reinterpret_cast<const char*>(src.data());
const char* end = ptr + src.size();
while (ptr < end) {
size_t rc = std::mbrtoc16(&c16, ptr, end - ptr, &state);
if (rc == (size_t) -1) return std::unexpected(ConvError::EncodeUtf8);
else if (rc == (size_t) -2) return std::unexpected(ConvError::IncompleteUtf8);
else if (rc != (size_t) -3) dst.push_back(c16); // from earlier surrogate pair
else {
dst.push_back(c16);
ptr += rc;
}
}
return dst;
}
// UTF16 -> UTF8
ConvResult<std::u8string> to_utf8(const std::u16string_view& src) {
std::u8string dst;
dst.reserve(src.size() * MULTIPLE_UTF16_TO_UTF8);
std::mbstate_t state{};
char mbout[MB_LEN_MAX]{};
for (char16_t c : src) {
size_t rc = std::c16rtomb(mbout, c, &state);
if (rc != (size_t) -1) dst.append(reinterpret_cast<char8_t*>(mbout), rc);
else return std::unexpected(ConvError::InvalidUtf16);
}
return dst;
}
// UTF8 -> UTF32
ConvResult<std::u32string> to_utf32(const std::u8string_view& src) {
std::u32string dst;
dst.reserve(src.size() * MULTIPLE_UTF8_TO_UTF32);
std::mbstate_t state{};
char32_t c32;
const char* ptr = reinterpret_cast<const char*>(src.data());
const char* end = ptr + src.size();
while (ptr < end) {
size_t rc = std::mbrtoc32(&c32, ptr, end - ptr, &state);
if (rc == (size_t) -1) return std::unexpected(ConvError::EncodeUtf8);
else if (rc == (size_t) -2) return std::unexpected(ConvError::IncompleteUtf8);
else if (rc != (size_t) -3) throw std::runtime_error("no surrogates in UTF-32");
else dst.push_back(c32);
ptr += rc;
}
return dst;
}
// UTF32 -> UTF8
ConvResult<std::u8string> to_utf8(const std::u32string_view& src) {
std::u8string dst;
dst.reserve(src.size() * MULTIPLE_UTF32_TO_UTF8);
std::mbstate_t state{};
char mbout[MB_LEN_MAX]{};
for (char32_t c : src) {
size_t rc = std::c32rtomb(mbout, c, &state);
if (rc != (size_t) -1) dst.append(reinterpret_cast<char8_t*>(mbout), rc);
else return std::unexpected(ConvError::InvalidUtf32);
}
return dst;
}
#pragma endregion
} // namespace yycc::encoding::windows
#endif

View File

@ -0,0 +1,121 @@
#pragma once
#include "../macro/os_detector.hpp"
#if defined(YYCC_OS_WINDOWS)
#include <string>
#include <string_view>
#include <expected>
#include <cstdint>
namespace yycc::encoding::windows {
/// @brief The type of Windows code page.
using CodePage = uint32_t;
/// @brief The possible error kind occurs in this module.
enum class ConvError {
TooLargeLength, ///< The length of given string is too large exceeding the maximum capacity of Win32 function.
NoDesiredSize, ///< Can not compute the desired size of result string.
BadWrittenSize, ///< The size of written data is not matched with expected size.
InvalidUtf32, ///< Given char is invalid in UTF32.
InvalidUtf16, ///< Given char is invalid in UTF16.
EncodeUtf8, ///< Error occurs when encoding UTF8.
IncompleteUtf8, ///< Given UTF8 string is incomplete.
};
/// @brief The result type in this module.
template<typename T>
using ConvResult = std::expected<T, ConvError>;
/**
* @brief WChar -> Char
* @param src
* @param code_page
* @return
*/
ConvResult<std::string> to_char(const std::wstring_view& src, CodePage code_page);
/**
* @brief Char -> WChar
* @param src
* @param code_page
* @return
*/
ConvResult<std::wstring> to_wchar(const std::string_view& src, CodePage code_page);
/**
* @brief Char -> Char
* @details This is the combination of "WChar -> Char" and "Char -> WChar"
* @param src
* @param src_code_page
* @param dst_code_page
* @return
*/
ConvResult<std::string> to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page);
/**
* @brief WChar -> UTF8
* @details This is the specialization of "WChar -> Char"
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::wstring_view& src);
/**
* @brief UTF8 -> WChar
* @details This is the specialization of "Char -> WChar"
* @param src
* @return
*/
ConvResult<std::wstring> to_wchar(const std::u8string_view& src);
/**
* @brief Char -> UTF8
* @details This is the specialization of "Char -> Char"
* @param src
* @param code_page
* @return
*/
ConvResult<std::u8string> to_utf8(const std::string_view& src, CodePage code_page);
/**
* @brief UTF8 -> Char
* @details This is the specialization of "Char -> Char"
* @param src
* @param code_page
* @return
*/
ConvResult<std::string> to_char(const std::u8string_view& src, CodePage code_page);
/**
* @brief UTF8 -> UTF16
* @param src
* @return
*/
ConvResult<std::u16string> to_utf16(const std::u8string_view& src);
/**
* @brief UTF16 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u16string_view& src);
/**
* @brief UTF8 -> UTF32
* @param src
* @return
*/
ConvResult<std::u32string> to_utf32(const std::u8string_view& src);
/**
* @brief UTF32 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u32string_view& src);
} // namespace yycc::encoding::windows
#endif

View File

@ -0,0 +1,30 @@
#pragma once
#if (defined(YYCC_CC_MSVC) + defined(YYCC_CC_GCC) + defined(YYCC_CC_CLANG)) != 1
#error "Current compiler is not supported!"
#endif
namespace yycc::macro::compiler {
/// @brief The kind of compiler.
enum class CompilerKind {
Msvc, ///< MSVC
Gcc, ///< GCC
Clang, ///< Clang
};
/**
* @brief Fetch the compiler type.
* @return The kind of compiler.
*/
inline constexpr CompilerKind get_compiler() {
#if defined(YYCC_CC_MSVC)
return CompilerKind::Msvc;
#elif defined(YYCC_CC_GCC)
return CompilerKind::Gcc;
#else
return CompilerKind::Clang;
#endif
}
} // namespace yycc::macro::compiler

View File

@ -0,0 +1,28 @@
#pragma once
// Check endian
#if (defined(YYCC_ENDIAN_LITTLE) + defined(YYCC_ENDIAN_BIG)) != 1
#error "Current system endian (byte order) is not supported!"
#endif
namespace yycc::macro::endian {
/// @brief The endian kind of OS.
enum class EndianKind {
Little, ///< Little endian.
Big, ///< Big endian.
};
/**
* @brief Fetch the endian of OS.
* @return The endian of OS.
*/
inline constexpr EndianKind get_endian() {
#if defined(YYCC_ENDIAN_LITTLE)
return EndianKind::Little;
#else
return EndianKind::Big;
#endif
}
} // namespace yycc::macro::endian

View File

@ -1,54 +0,0 @@
#pragma once
// Hint for C++ feature detection:
// __cplusplus macro need special compiler switch enabled when compiling.
// So we use _MSVC_LANG check it instead.
// ===== C++ Version =====
// Detect C++ 20
#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
#define YYCC_CPPFEAT_GE_CPP20
#endif
// Detect C++ 23
#if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)
#define YYCC_CPPFEAT_GE_CPP23
#endif
// ===== C++ Features =====
// Check whether there is support of UTF8 string system.
#if defined(__cpp_char8_t) || defined(YYCC_CPPFEAT_GE_CPP20)
#define YYCC_CPPFEAT_UTF8
#endif
// Check whether there is support of `contains` for `set` and `map` including their varients.
#if defined(YYCC_CPPFEAT_GE_CPP20)
#define YYCC_CPPFEAT_CONTAINS
#endif
// Check whether there is support of `starts_with` and `ends_with` for `basic_string`.
#if defined(__cpp_lib_starts_ends_with) || defined(YYCC_CPPFEAT_GE_CPP20)
#define YYCC_CPPFEAT_STARTS_ENDS_WITH
#endif
// Check whether there is support of `std::expected`.
#if defined(__cpp_lib_expected) || defined(YYCC_CPPFEAT_GE_CPP23)
#define YYCC_CPPFEAT_EXPECTED
#endif
// Check whether there is support of `std::format`.
#if defined(YYCC_CPPFEAT_GE_CPP20)
#define YYCC_CPPFEAT_FORMAT
#endif
// Check whether there is support of `__VA_OPT__`
#if defined(YYCC_CPPFEAT_GE_CPP20)
#define YYCC_CPPFEAT_VA_OPT
#endif
// Check whether there is support of `std::stacktrace` and its formatter.
#if (defined(__cpp_lib_starts_ends_with) && defined(__cpp_lib_formatters)) || defined(YYCC_CPPFEAT_GE_CPP23)
#define YYCC_CPPFEAT_STACKTRACE
#endif

View File

@ -1,11 +1,28 @@
#pragma once
// Define operating system macros
#define YYCC_OS_WINDOWS 2
#define YYCC_OS_LINUX 3
// Check current operating system.
#if defined(_WIN32)
#define YYCC_OS YYCC_OS_WINDOWS
#else
#define YYCC_OS YYCC_OS_LINUX
// Check OS macro
#if (defined(YYCC_OS_WINDOWS) + defined(YYCC_OS_LINUX)) != 1
#error "Current operating system is not supported!"
#endif
namespace yycc::macro::os {
/// @brief The operating system kind.
enum class OsKind {
Windows, ///< Microsoft Windows
Linux, ///< GNU/Linux
};
/**
* @brief Fetch the operating system
* @return The kind of operating system.
*/
inline constexpr OsKind get_os() {
#if defined(YYCC_OS_WINDOWS)
return OsKind::Windows;
#else
return OsKind::Linux;
#endif
}
} // namespace yycc::macro::os

View File

@ -1,13 +1,12 @@
#pragma once
#include "../string.hpp"
#include "../string/op.hpp"
#include "../string/reinterpret.hpp"
#include <string_view>
#include <type_traits>
#include <charconv>
#include <stdexcept>
#include <type_traits>
#include <variant>
#include <expected>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
#define NS_YYCC_STRING_OP ::yycc::string::op
@ -20,18 +19,16 @@
*/
namespace yycc::num::parse {
/// @private
/// @brief The error kind when parsing string into number.
enum class ParseError {
PartiallyParsed, ///< Only a part of given string was parsed. The whole string may be invalid.
InvalidString, ///< Given string is a invalid number string.
OutOfRange, ///< Given string is valid but its value out of the range of given number type.
OutOfRange, ///< Given string is valid but its value out of the range of given number type.
};
/// @private
/// @brief The return value of internal parse function which ape `std::expected`.
template<typename T, std::enable_if_t<!std::is_same_v<T, ParseError>, int> = 0>
using ParseResult = std::variant<T, ParseError>;
template<typename T>
using ParseResult = std::expected<T, ParseError>;
/**
* @private
@ -41,8 +38,9 @@ namespace yycc::num::parse {
* @param fmt The floating point format to use
* @return ParseResult<T> containing either the parsed value or a ParseError
*/
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl, std::chars_format fmt) {
template<typename T>
requires(std::is_floating_point_v<T>)
ParseResult<T> parse(const std::u8string_view& strl, std::chars_format fmt) {
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
T rv;
@ -54,13 +52,13 @@ namespace yycc::num::parse {
// Parse completely.
// But we need to check whether the whole string was parsed.
if (ptr == tail) return rv;
else return ParseError::PartiallyParsed;
else return std::unexpected(ParseError::PartiallyParsed);
} else if (ec == std::errc::invalid_argument) {
// Given string is invalid
return ParseError::InvalidString;
return std::unexpected(ParseError::InvalidString);
} else if (ec == std::errc::result_out_of_range) {
// Given string is out of range
return ParseError::OutOfRange;
return std::unexpected(ParseError::OutOfRange);
} else {
// Unreachable
throw std::runtime_error("invalid ec.");
@ -75,8 +73,9 @@ namespace yycc::num::parse {
* @param base Numeric base (2-36)
* @return ParseResult<T> containing either the parsed value or a ParseError
*/
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl, int base) {
template<typename T>
requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
ParseResult<T> parse(const std::u8string_view& strl, int base) {
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
T rv;
@ -88,13 +87,13 @@ namespace yycc::num::parse {
// Parse completely.
// But we need to check whether the whole string was parsed.
if (ptr == tail) return rv;
else return ParseError::PartiallyParsed;
else return std::unexpected(ParseError::PartiallyParsed);
} else if (ec == std::errc::invalid_argument) {
// Given string is invalid
return ParseError::InvalidString;
return std::unexpected(ParseError::InvalidString);
} else if (ec == std::errc::result_out_of_range) {
// Given string is out of range
return ParseError::OutOfRange;
return std::unexpected(ParseError::OutOfRange);
} else {
// Unreachable
throw std::runtime_error("invalid ec.");
@ -108,141 +107,18 @@ namespace yycc::num::parse {
* @param strl The UTF-8 string view to parse ("true" or "false", case insensitive)
* @return ParseResult<bool> containing either the parsed value or a ParseError
*/
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl) {
template<typename T>
requires(std::is_same_v<T, bool>)
ParseResult<T> parse(const std::u8string_view& strl) {
// Get lower case
auto lower_case = NS_YYCC_STRING_OP::to_lower(strl);
// Compare result
if (lower_case == YYCC_U8("true")) return true;
else if (lower_case == YYCC_U8("false")) return false;
if (lower_case == u8"true") return true;
else if (lower_case == u8"false") return false;
else return ParseError::InvalidString;
}
/**
* @brief Try parsing given string to floating point types.
* @tparam T The type derived from floating point type.
* @param[in] strl The string need to be parsed.
* @param[out] num
* The variable receiving result.
* There is no guarantee that the content is not modified when parsing failed.
* @param[in] fmt The floating point format used when try parsing.
* @return True if success, otherwise false.
*/
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
bool try_parse(const NS_YYCC_STRING::u8string_view& strl,
T& num,
std::chars_format fmt = std::chars_format::general) {
auto rv = priv_parse<T>(strl, fmt);
if (const auto* ptr = std::get_if<T>(&rv)) {
num = *ptr;
return true;
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
return false;
} else {
// Unreachable
throw std::runtime_error("unreachable code.");
}
}
/**
* @brief Try parsing given string to integral types.
* @tparam T The type derived from integral type except bool type.
* @param[in] strl The string need to be parsed.
* @param[out] num
* The variable receiving result.
* There is no guarantee that the content is not modified when parsing failed.
* @param[in] base Integer base to use: a value between 2 and 36 (inclusive).
* @return True if success, otherwise false.
*/
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num, int base = 10) {
auto rv = priv_parse<T>(strl, base);
if (const auto* ptr = std::get_if<T>(&rv)) {
num = *ptr;
return true;
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
return false;
} else {
// Unreachable
throw std::runtime_error("unreachable code.");
}
}
/**
* @brief Try parsing given string to bool types.
* @tparam T The type derived from bool type.
* @param[in] strl The string need to be parsed ("true" or "false", case insensitive).
* @param[out] num
* The variable receiving result.
* There is no guarantee that the content is not modified when parsing failed.
* @return True if success, otherwise false.
*/
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num) {
auto rv = priv_parse<T>(strl);
if (const auto* ptr = std::get_if<T>(&rv)) {
num = *ptr;
return true;
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
return false;
} else {
// Unreachable
throw std::runtime_error("unreachable code.");
}
}
/**
* @brief Parse given string to floating point types.
* @tparam T The type derived from floating point type.
* @param[in] strl The string need to be parsed.
* @param[in] fmt The floating point format used when try parsing.
* @return
* The parsing result.
* There is no guarantee about the content of this return value when parsing failed.
* It may be any possible value but usually is its default value.
* @exception std::invalid_argument Can not parse given string.
*/
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
T parse(const NS_YYCC_STRING::u8string_view& strl,
std::chars_format fmt = std::chars_format::general) {
T rv;
if (try_parse(strl, rv, fmt)) return rv;
else throw std::invalid_argument("can not parse given string");
}
/**
* @brief Parse given string to integral type types.
* @tparam T The type derived from integral type except bool type.
* @param[in] strl The string need to be parsed.
* @param[in] base Integer base to use: a value between 2 and 36 (inclusive).
* @return
* The parsing result.
* There is no guarantee about the content of this return value when parsing failed.
* It may be any possible value but usually is its default value.
* @exception std::invalid_argument Can not parse given string.
*/
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
T parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) {
T rv;
if (try_parse(strl, rv, base)) return rv;
else throw std::invalid_argument("can not parse given string");
}
/**
* @brief Parse given string to bool types.
* @tparam T The type derived from bool type.
* @param[in] strl The string need to be parsed ("true" or "false", case insensitive).
* @return
* The parsing result.
* There is no guarantee about the content of this return value when parsing failed.
* It may be any possible value but usually is its default value.
* @exception std::invalid_argument Can not parse given string.
*/
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
T parse(const NS_YYCC_STRING::u8string_view& strl) {
T rv;
if (try_parse(strl, rv)) return rv;
else throw std::invalid_argument("can not parse given string");
}
} // namespace yycc::string::parse
} // namespace yycc::num::parse
#undef NS_YYCC_STRING_OP
#undef NS_YYCC_STRING_REINTERPRET
#undef NS_YYCC_STRING

View File

@ -1,12 +1,11 @@
#pragma once
#include "../string.hpp"
#include "../string/reinterpret.hpp"
#include <string>
#include <array>
#include <type_traits>
#include <charconv>
#include <stdexcept>
#include <type_traits>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
/**
@ -25,7 +24,7 @@ namespace yycc::num::stringify {
inline constexpr size_t STRINGIFY_BUFFER_SIZE = 64u;
/// @private
/// @brief Type alias for the buffer used in string conversion.
using StringifyBuffer = std::array<NS_YYCC_STRING::u8char, STRINGIFY_BUFFER_SIZE>;
using StringifyBuffer = std::array<char8_t, STRINGIFY_BUFFER_SIZE>;
/**
* @brief Return the string representation of given floating point value.
@ -35,10 +34,9 @@ namespace yycc::num::stringify {
* @param[in] precision The floating point precision used when getting string representation.
* @return The string representation of given value.
*/
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
NS_YYCC_STRING::u8string stringify(T num,
std::chars_format fmt = std::chars_format::general,
int precision = 6) {
template<typename T>
requires(std::is_floating_point_v<T>)
std::u8string stringify(T num, std::chars_format fmt = std::chars_format::general, int precision = 6) {
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
StringifyBuffer buffer;
@ -48,8 +46,7 @@ namespace yycc::num::stringify {
fmt,
precision);
if (ec == std::errc()) {
return NS_YYCC_STRING::u8string(buffer.data(),
reinterpret::as_utf8(ptr) - buffer.data());
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
} else if (ec == std::errc::value_too_large) {
// Too short buffer. This should not happen.
throw std::out_of_range("stringify() buffer is not sufficient.");
@ -65,18 +62,18 @@ namespace yycc::num::stringify {
* @param[in] base Integer base used when getting string representation: a value between 2 and 36 (inclusive).
* @return The string representation of given value.
*/
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
NS_YYCC_STRING::u8string stringify(T num, int base = 10) {
template<typename T>
requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
std::u8string stringify(T num, int base = 10) {
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
StringifyBuffer buffer;
auto [ptr, ec] = std::to_chars(reinterpret::as_ordinary(buffer.data()),
reinterpret::as_ordinary(buffer.data() + buffer.size()),
num,
base);
if (ec == std::errc()) {
return NS_YYCC_STRING::u8string(buffer.data(),
reinterpret::as_utf8(ptr) - buffer.data());
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
} else if (ec == std::errc::value_too_large) {
// Too short buffer. This should not happen.
throw std::out_of_range("stringify() buffer is not sufficient.");
@ -91,13 +88,13 @@ namespace yycc::num::stringify {
* @param[in] num The value need to get string representation.
* @return The string representation of given value ("true" or "false").
*/
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
NS_YYCC_STRING::u8string stringify(T num) {
if (num) return NS_YYCC_STRING::u8string(YYCC_U8("true"));
else return NS_YYCC_STRING::u8string(YYCC_U8("false"));
template<typename T>
requires(std::is_same_v<T, bool>)
std::u8string stringify(T num) {
if (num) return std::u8string(u8"true");
else return std::u8string(u8"false");
}
} // namespace yycc::string::stringify
} // namespace yycc::num::stringify
#undef NS_YYCC_STRING_REINTERPRET
#undef NS_YYCC_STRING

View File

@ -1,45 +0,0 @@
#pragma once
#include "../macro/feature_probe.hpp"
namespace yycc::patch::contains {
/**
* @brief Checks if there is an element with key equivalent to key in the container.
* @details
* The polyfill to \c contains() function of unordered and ordered associative container.
* Because this function only present after C++ 20.
* This function will use our custom polyfill if the version of C++ standard you are using lower than C++ 20.
* Otherwise it will fallback to vanilla standard library function.
* @tparam TContainer
* The type of container. This container must have \c find() and \c end() member functions.
* @tparam TKey
* The type of key of container.
* If the container is a set, this type is the type of item in set.
* If the container is a map, this type is the key type of map.
* @param[in] container The reference to container to find.
* @param[in] key Key value of the element to search for
* @return True if there is such an element, otherwise false.
* @remarks
* This template function do not have constraint check.
* If container type has \c find() and \c end() member functions, this template function will be created without any error.
* However, this function should be used for standard library associative container according to its original purpose.
* It means that the type of container usually and should be one of following types:
* \li \c std::set
* \li \c std::multiset
* \li \c std::map
* \li \c std::multimap
* \li \c std::unordered_set
* \li \c std::unordered_multiset
* \li \c std::unordered_map
* \li \c std::unordered_multimap
*/
template<class TContainer, class TKey>
bool contains(const TContainer& container, const TKey& key) {
#if defined(YYCC_CPPFEAT_CONTAINS)
return container.contains(key);
#else
return container.find(key) != container.end();
#endif
}
} // namespace yycc::patch::container

View File

@ -1,48 +0,0 @@
#include "path.hpp"
#include "../macro/os_detector.hpp"
#include <stdexcept>
#define NS_YYCC_STRING ::yycc::string
namespace yycc::patch::path {
// TODO: Fix this after finish encoding parts.
// TODO: Add native implementation if C++ support it.
// So we need add feature test macro at the same time.
std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path) {
// #if YYCC_OS == YYCC_OS_WINDOWS
// // convert path to wchar
// std::wstring wpath;
// if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath))
// throw std::invalid_argument("Fail to convert given UTF8 string.");
// // return path with wchar_t ctor
// return std::filesystem::path(wpath);
// #else
// std::string cache = YYCC::EncodingHelper::ToOrdinary(u8_path);
// return std::filesystem::path(cache.c_str());
// #endif
return std::filesystem::path();
}
NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path) {
// #if YYCC_OS == YYCC_OS_WINDOWS
// // get and convert to utf8
// NS_YYCC_STRING::u8string u8_path;
// if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path))
// throw std::invalid_argument("Fail to convert to UTF8 string.");
// // return utf8 path
// return u8_path;
// #else
// return EncodingHelper::ToUTF8(path.string());
// #endif
return NS_YYCC_STRING::u8string();
}
}

View File

@ -1,32 +0,0 @@
#pragma once
#include "../string.hpp"
#include <filesystem>
#define NS_YYCC_STRING ::yycc::string
/**
* @brief \c Standard library related patches for UTF8 compatibility and the limitation of C++ standard version.
* @details
* See also \ref std_patch.
*/
namespace yycc::patch::path {
/**
* @brief Constructs \c std::filesystem::path from UTF8 path.
* @param[in] u8_path UTF8 path string for building.
* @return \c std::filesystem::path instance.
* @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?).
*/
std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path);
/**
* @brief Returns the UTF8 representation of given \c std::filesystem::path.
* @param[in] path The \c std::filesystem::path instance converting to UTF8 path.
* @return The UTF8 representation of given \c std::filesystem::path.
* @exception std::invalid_argument Fail to convert to UTF8 string.
*/
NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path);
} // namespace yycc::patch::path
#undef NS_YYCC_STRING

View File

@ -1,203 +0,0 @@
#pragma once
#include "../macro/feature_probe.hpp"
#include <string>
#include <string_view>
namespace yycc::patch::starts_ends_with {
// Reference:
// https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with
// https://en.cppreference.com/w/cpp/string/basic_string_view/ends_with
// https://en.cppreference.com/w/cpp/string/basic_string/starts_with
// https://en.cppreference.com/w/cpp/string/basic_string/ends_with
#pragma region For String View
/**
* @brief Checks if the string view begins with the given prefix
* @param[in] that The string view to find.
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string_view<CharT, Traits>& that,
std::basic_string_view<CharT, Traits> sv) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(sv);
#else
return std::basic_string_view<CharT, Traits>(that.data(), std::min(that.size(), sv.size()))
== sv;
#endif
}
/**
* @brief Checks if the string view begins with the given prefix
* @param[in] that The string view to find.
* @param[in] ch A single character.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string_view<CharT, Traits>& that, CharT ch) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(ch);
#else
return !that.empty() && Traits::eq(that.front(), ch);
#endif
}
/**
* @brief Checks if the string view begins with the given prefix
* @param[in] that The string view to find.
* @param[in] s A null-terminated character string.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string_view<CharT, Traits>& that, const CharT* s) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(s);
#else
return starts_with(that, std::basic_string_view(s));
#endif
}
/**
* @brief Checks if the string view ends with the given suffix
* @param[in] that The string view to find.
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string_view<CharT, Traits>& that,
std::basic_string_view<CharT, Traits> sv) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(sv);
#else
return that.size() >= sv.size()
&& that.compare(that.size() - sv.size(),
std::basic_string_view<CharT, Traits>::npos,
sv)
== 0;
#endif
}
/**
* @brief Checks if the string view ends with the given suffix
* @param[in] that The string view to find.
* @param[in] ch A single character.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string_view<CharT, Traits>& that, CharT ch) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(ch);
#else
return !that.empty() && Traits::eq(that.back(), ch);
#endif
}
/**
* @brief Checks if the string view ends with the given suffix
* @param[in] that The string view to find.
* @param[in] s A null-terminated character string.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string_view<CharT, Traits>& that, const CharT* s) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(s);
#else
return ends_with(that, std::basic_string_view(s));
#endif
}
#pragma endregion
#pragma region For String
/**
* @brief Checks if the string begins with the given prefix
* @param[in] that The string to find.
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string<CharT, Traits>& that,
std::basic_string_view<CharT, Traits> sv) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(sv);
#else
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), sv);
#endif
}
/**
* @brief Checks if the string begins with the given prefix
* @param[in] that The string to find.
* @param[in] ch A single character.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(ch);
#else
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), ch);
#endif
}
/**
* @brief Checks if the string begins with the given prefix
* @param[in] that The string to find.
* @param[in] s A null-terminated character string.
* @return True if the string view begins with the provided prefix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool starts_with(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.starts_with(s);
#else
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), s);
#endif
}
/**
* @brief Checks if the string ends with the given suffix
* @param[in] that The string to find.
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string<CharT, Traits>& that,
std::basic_string_view<CharT, Traits> sv) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(sv);
#else
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), sv);
#endif
}
/**
* @brief Checks if the string ends with the given suffix
* @param[in] that The string to find.
* @param[in] ch A single character.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(ch);
#else
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), ch);
#endif
}
/**
* @brief Checks if the string ends with the given suffix
* @param[in] that The string to find.
* @param[in] s A null-terminated character string.
* @return True if the string view ends with the provided suffix, false otherwise.
*/
template<class CharT, class Traits = std::char_traits<CharT>>
bool ends_with(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
return that.ends_with(s);
#else
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), s);
#endif
}
#pragma endregion
} // namespace yycc::patch::starts_ends_with

View File

@ -1,18 +0,0 @@
#pragma once
// Prelude section
#include "../string.hpp"
namespace yycc::prelude {
#define NS_YYCC_STRING ::yycc::string
using u8char = NS_YYCC_STRING::u8char;
using u8string = NS_YYCC_STRING::u8string;
using u8string_view = NS_YYCC_STRING::u8string_view;
#undef NS_YYCC_STRING
} // namespace yycc::prelude
// Expose all members
using namespace yycc::prelude;

View File

@ -1,99 +0,0 @@
#pragma once
#include "../../macro/feature_probe.hpp"
#include "../../num/parse.hpp"
#include "../panic.hpp"
#include "../result.hpp"
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_NUM_PARSE ::yycc::num::parse
#define NS_YYCC_RUST_RESULT ::yycc::rust::result
/**
* @namespace yycc::rust::parse
* @brief Provides Rust-inspired parsing utilities for converting strings to various types.
* @details
* This namespace contains template functions for parsing strings into different types
* (floating-point, integral, boolean) with Rust-like Result error handling.
*/
namespace yycc::rust::num::parse {
#if defined(YYCC_CPPFEAT_EXPECTED)
/// @brief The error type of parsing.
using Error = NS_YYCC_NUM_PARSE::ParseError;
/// @brief The result type of parsing.
/// @tparam T The expected value type in result.
template<typename T>
using Result = NS_YYCC_RUST_RESULT::Result<T, Error>;
/**
* @brief Parses a string into a floating-point value.
* @tparam T Floating-point type to parse into (float, double, etc.)
* @param strl String view to parse
* @param fmt Formatting flags for parsing (default: general)
* @return Result<T> containing either the parsed value or an error
*/
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl,
std::chars_format fmt = std::chars_format::general) {
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl, fmt);
if (const auto* ptr = std::get_if<T>(&rv)) {
return NS_YYCC_RUST_RESULT::Ok<Result<T>>(*ptr);
} else if (const auto* ptr = std::get_if<Error>(&rv)) {
return NS_YYCC_RUST_RESULT::Err<Result<T>>(*ptr);
} else {
// Unreachable
RS_PANIC("unreachable code.");
}
}
/**
* @brief Parses a string into an integral value (excluding bool).
* @tparam T Integral type to parse into (int, long, etc.)
* @param strl String view to parse
* @param base Numeric base for parsing (default: 10)
* @return Result<T> containing either the parsed value or an error
*/
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) {
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl, base);
if (const auto* ptr = std::get_if<T>(&rv)) {
return NS_YYCC_RUST_RESULT::Ok<Result<T>>(*ptr);
} else if (const auto* ptr = std::get_if<Error>(&rv)) {
return NS_YYCC_RUST_RESULT::Err<Result<T>>(*ptr);
} else {
// Unreachable
RS_PANIC("unreachable code.");
}
}
/**
* @brief Parses a string into a boolean value.
* @tparam T Must be bool type
* @param strl String view to parse
* @return Result<bool> containing either the parsed value or an error
*/
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl) {
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl);
if (const auto* ptr = std::get_if<T>(&rv)) {
return NS_YYCC_RUST_RESULT::Ok<Result<T>>(*ptr);
} else if (const auto* ptr = std::get_if<Error>(&rv)) {
return NS_YYCC_RUST_RESULT::Err<Result<T>>(*ptr);
} else {
// Unreachable
RS_PANIC("unreachable code.");
}
}
#endif
}
#undef NS_YYCC_RUST_RESULT
#undef NS_YYCC_NUM_PARSE
#undef NS_YYCC_STRING

View File

@ -1,10 +0,0 @@
#pragma once
#include "../../num/stringify.hpp"
namespace yycc::rust::num::stringify {
// There is no modification for legacy "stringify" functions like "parse".
// So we simply expose all functions into this namespace.
using namespace ::yycc::num::stringify;
} // namespace yycc::rust::stringify

View File

@ -1,10 +1,12 @@
#pragma once
#include <optional>
/// @brief The reproduction of Rust Option type.
/// @details
/// This namespace reproduce Rust Option type, and its members Some and None in C++.
/// However Option is not important than Result, so its implementation is very casual.
/**
* @brief The reproduction of Rust Option type.
* @details
* This namespace reproduce Rust Option type, and its members Some and None in C++.
* However Option is not important than Result, so its implementation is very casual.
*/
namespace yycc::rust::option {
template<typename T>

View File

@ -1,12 +1,9 @@
#include "panic.hpp"
#include "../macro/feature_probe.hpp"
#include <cstdlib>
#include <iomanip>
#include <iostream>
#if defined(YYCC_CPPFEAT_STACKTRACE)
#include <stacktrace>
#endif
namespace yycc::rust::panic {
@ -24,12 +21,8 @@ namespace yycc::rust::panic {
// User custom message
dst << "note: " << msg << std::endl;
// Stacktrace message if we support it.
#if defined(YYCC_CPPFEAT_STACKTRACE)
dst << "stacktrace: " << std::endl;
dst << std::stacktrace::current() << std::endl;
#else
dst << "there is no stacktrace because your C++ runtime do not support it." << std::endl;
#endif
// // Restore color
// dst << RESET;

View File

@ -1,10 +1,6 @@
#pragma once
#include "../macro/feature_probe.hpp"
#include <string_view>
#if defined(YYCC_CPPFEAT_FORMAT)
#include <format>
#endif
/**
* @brief Provides Rust-style panic functionality for immediate program termination on unrecoverable errors.
@ -38,13 +34,7 @@ namespace yycc::rust::panic {
* The macro parameters are the message to format and its arguments, following \c std::format syntax.
* This macro essentially calls \c std::format internally.
*/
#if defined(YYCC_CPPFEAT_FORMAT)
#if defined(YYCC_CPPFEAT_VA_OPT)
#define RS_PANICF(msg, ...) RS_PANIC(std::format(msg __VA_OPT__(, ) __VA_ARGS__))
#else
#define RS_PANICF(msg, ...) RS_PANIC(std::format(msg, ##__VA_ARGS__))
#endif
#endif
/**
* @brief Immediately crashes the entire program like Rust's \c panic! macro.

View File

@ -1,16 +1,13 @@
#pragma once
// Include YYCC prelude first
#include "core.hpp"
// Rust prelude section
#include "../rust/primitive.hpp"
#include "../rust/result.hpp"
#include "../rust/option.hpp"
#include "../rust/panic.hpp"
#include "primitive.hpp"
#include "result.hpp"
#include "option.hpp"
#include "panic.hpp"
#include <vector>
namespace yycc::prelude::rust {
namespace yycc::rust::prelude {
// Include primitive types
#define NS_RUST_PRIMITIVE ::yycc::rust::primitive
@ -35,7 +32,7 @@ namespace yycc::prelude::rust {
#undef NS_RUST_PRIMITIVE
// Other types
using String = ::yycc::string::u8string;
using String = std::u8string;
template<typename T>
using Vec = std::vector<T>;
@ -49,4 +46,4 @@ namespace yycc::prelude::rust {
} // namespace yycc::prelude::rust
// Expose all members
using namespace yycc::prelude::rust;
using namespace ::yycc::rust::prelude;

View File

@ -1,7 +1,7 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include "../string.hpp"
#include <string_view>
namespace yycc::rust::primitive {
@ -23,6 +23,6 @@ namespace yycc::rust::primitive {
using f32 = float;
using f64 = double;
using str = ::yycc::string::u8string_view;
using str = std::u8string_view;
}

View File

@ -1,9 +1,5 @@
#pragma once
#include "../macro/feature_probe.hpp"
#if defined(YYCC_CPPFEAT_EXPECTED)
#include <expected>
#endif
/**
* @brief The reproduction of Rust Option type.
@ -42,8 +38,6 @@
*/
namespace yycc::rust::result {
#if defined(YYCC_CPPFEAT_EXPECTED)
/**
* @brief Equivalent Rust \c Result in C++
* @tparam T The type of the expected value.
@ -80,6 +74,4 @@ namespace yycc::rust::result {
return ResultType(std::unexpect, std::forward<Args>(args)...);
}
#endif
} // namespace yycc::rust::result

View File

@ -1,47 +0,0 @@
#pragma once
// Define the UTF8 char type we used.
// And do a polyfill if no embedded char8_t type.
#include "macro/feature_probe.hpp"
#include <string>
#include <string_view>
namespace yycc::string {
/**
\typedef u8char_t
\brief YYCC UTF8 char type.
\details
This char type is an alias to \c char8_t if your current C++ standard support it.
Otherwise it is defined as <TT>unsigned char</TT> as C++ 20 stdandard does.
*/
/**
\typedef u8string
\brief YYCC UTF8 string container type.
\details
This type is defined as \c std::basic_string<yycc_char8_t>.
It is equal to \c std::u8string if your current C++ standard support it.
*/
/**
\typedef u8string_view
\brief YYCC UTF8 string view type.
\details
This type is defined as \c std::basic_string_view<yycc_char8_t>.
It is equal to \c std::u8string_view if your current C++ standard support it.
*/
#if defined(YYCC_CPPFEAT_UTF8)
using u8char = char8_t;
using u8string = std::u8string;
using u8string_view = std::u8string_view;
#else
using u8char = unsigned char;
using u8string = std::basic_string<u8char>;
using u8string_view = std::basic_string_view<u8char>;
#endif
#define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8.
#define YYCC_U8(strl) (reinterpret_cast<const ::yycc::string::u8char*>(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding.
#define YYCC_U8_CHAR(chr) (static_cast<::yycc::string::u8char>(chr)) ///< The macro for casting ordinary char type into YYCC UTF8 char type.
} // namespace yycc::string

View File

@ -1,196 +1,180 @@
#include "op.hpp"
#include <algorithm>
#include "reinterpret.hpp"
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
namespace yycc::string::op {
#pragma region Printf VPrintf
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...) {
va_list argptr;
va_start(argptr, format);
bool ret = vprintf(strl, format, argptr);
va_end(argptr);
return ret;
}
template<typename TChar>
requires(sizeof(TChar) == sizeof(char))
static FormatResult<std::basic_string<TChar>> generic_printf(const TChar* format, va_list argptr) {
// Prepare result
std::basic_string<TChar> rv;
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr) {
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
// Check format
if (format == nullptr) return std::unexpected(FormatError::NullFormat);
va_list args1;
va_copy(args1, argptr);
va_list args2;
va_copy(args2, argptr);
// Prepare variable arguments
va_list args1;
va_copy(args1, argptr);
va_list args2;
va_copy(args2, argptr);
// the return value is desired char count without NULL terminal.
// minus number means error
int count = std::vsnprintf(
nullptr,
0,
reinterpret::as_ordinary(format),
args1
);
if (count < 0) {
// invalid length returned by vsnprintf.
return false;
}
va_end(args1);
// The return value is desired char count without NULL terminal.
// Minus number means error.
int count = std::vsnprintf(nullptr, 0, reinterpret_cast<const char*>(format), args1);
// Check expected size.
if (count < 0) {
// Invalid length returned by vsnprintf.
return std::unexpected(FormatError::NoDesiredSize);
}
va_end(args1);
// resize std::string to desired count.
// and pass its length + 1 to std::vsnprintf,
// because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
// however std::vsnprintf already have a trailing NULL, so we plus 1 for it.
strl.resize(count);
int write_result = std::vsnprintf(
reinterpret::as_ordinary(strl.data()),
strl.size() + 1,
reinterpret::as_ordinary(format),
args2
);
va_end(args2);
// Resize std::string to desired count, and pass its length + 1 to std::vsnprintf,
// Because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
// However std::vsnprintf already have a trailing NULL, so we plus 1 for it.
rv.resize(count);
int write_result = std::vsnprintf(reinterpret_cast<char*>(rv.data()), rv.size() + 1, reinterpret_cast<const char*>(format), args2);
va_end(args2);
// Check written size.
if (write_result < 0 || write_result > count) {
// Invalid write result in vsnprintf.
return std::unexpected(FormatError::BadWrittenSize);
}
if (write_result < 0 || write_result > count) {
// invalid write result in vsnprintf.
return false;
}
// Return value
return rv;
}
return true;
}
FormatResult<std::u8string> printf(const char8_t* format, ...) {
va_list argptr;
va_start(argptr, format);
auto rv = vprintf(format, argptr);
va_end(argptr);
return rv;
}
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...) {
NS_YYCC_STRING::u8string ret;
FormatResult<std::u8string> vprintf(const char8_t* format, va_list argptr) {
return generic_printf(format, argptr);
}
va_list argptr;
va_start(argptr, format);
vprintf(ret, format, argptr);
va_end(argptr);
FormatResult<std::string> printf(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
auto rv = vprintf(format, argptr);
va_end(argptr);
return rv;
}
return ret;
}
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr) {
NS_YYCC_STRING::u8string ret;
va_list argcpy;
va_copy(argcpy, argptr);
vprintf(ret, format, argcpy);
va_end(argcpy);
return ret;
}
FormatResult<std::string> vprintf(const char* format, va_list argptr) {
return generic_printf(format, argptr);
}
#pragma endregion
#pragma region Replace
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) {
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
// check requirements
// from string should not be empty
NS_YYCC_STRING::u8string from_strl(_from_strl);
NS_YYCC_STRING::u8string to_strl(_to_strl);
if (from_strl.empty()) return;
// check requirements
// from string should not be empty
std::u8string from_strl(_from_strl);
std::u8string to_strl(_to_strl);
if (from_strl.empty()) return;
// start replace one by one
size_t start_pos = 0;
while ((start_pos = strl.find(from_strl, start_pos)) != NS_YYCC_STRING::u8string::npos) {
strl.replace(start_pos, from_strl.size(), to_strl);
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
// start replace one by one
size_t start_pos = 0;
while ((start_pos = strl.find(from_strl, start_pos)) != std::u8string::npos) {
strl.replace(start_pos, from_strl.size(), to_strl);
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
// prepare result
NS_YYCC_STRING::u8string strl(_strl);
replace(strl, _from_strl, _to_strl);
// return value
return strl;
}
std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) {
// prepare result
std::u8string strl(_strl);
replace(strl, _from_strl, _to_strl);
// return value
return strl;
}
#pragma endregion
#pragma region Join
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter) {
NS_YYCC_STRING::u8string ret;
bool is_first = true;
NS_YYCC_STRING::u8string_view element;
std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter) {
std::u8string ret;
bool is_first = true;
std::u8string_view element;
// fetch element
while (fct_data(element)) {
// insert delimiter
if (is_first) is_first = false;
else {
// append delimiter.
ret.append(delimiter);
}
// fetch element
while (fct_data(element)) {
// insert delimiter
if (is_first) is_first = false;
else {
// append delimiter.
ret.append(delimiter);
}
// insert element if it is not empty
if (!element.empty())
ret.append(element);
}
// insert element if it is not empty
if (!element.empty()) ret.append(element);
}
return ret;
}
return ret;
}
#pragma endregion
#pragma region Upper Lower
template<bool BIsToLower>
static void generic_lower_upper(NS_YYCC_STRING::u8string& strl) {
// References:
// https://en.cppreference.com/w/cpp/algorithm/transform
// https://en.cppreference.com/w/cpp/string/byte/tolower
std::transform(
strl.cbegin(), strl.cend(), strl.begin(),
[](unsigned char c) -> char {
if constexpr (BIsToLower) return std::tolower(c);
else return std::toupper(c);
}
);
}
template<bool BIsToLower>
static void generic_lower_upper(std::u8string& strl) {
// References:
// https://en.cppreference.com/w/cpp/algorithm/transform
// https://en.cppreference.com/w/cpp/string/byte/tolower
std::transform(strl.cbegin(), strl.cend(), strl.begin(), [](unsigned char c) -> char {
if constexpr (BIsToLower) return std::tolower(c);
else return std::toupper(c);
});
}
void lower(NS_YYCC_STRING::u8string& strl) {
generic_lower_upper<true>(strl);
}
void lower(std::u8string& strl) {
generic_lower_upper<true>(strl);
}
NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl) {
NS_YYCC_STRING::u8string ret(strl);
lower(ret);
return ret;
}
std::u8string to_lower(const std::u8string_view& strl) {
std::u8string ret(strl);
lower(ret);
return ret;
}
void upper(NS_YYCC_STRING::u8string& strl) {
generic_lower_upper<false>(strl);
}
void upper(std::u8string& strl) {
generic_lower_upper<false>(strl);
}
NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl) {
// same as Lower, just replace char transform function.
NS_YYCC_STRING::u8string ret(strl);
upper(ret);
return ret;
}
std::u8string to_upper(const std::u8string_view& strl) {
// same as Lower, just replace char transform function.
std::u8string ret(strl);
upper(ret);
return ret;
}
#pragma endregion
#pragma region Split
std::vector<NS_YYCC_STRING::u8string_view> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) {
std::vector<std::u8string_view> split(const std::u8string_view& strl, const std::u8string_view& _delimiter) {
// Reference:
// https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
// prepare return value
std::vector<NS_YYCC_STRING::u8string_view> elems;
std::vector<std::u8string_view> elems;
// if string need to be splitted is empty, return original string (empty string).
// if delimiter is empty, return original string.
NS_YYCC_STRING::u8string delimiter(_delimiter);
std::u8string delimiter(_delimiter);
if (strl.empty() || delimiter.empty()) {
elems.emplace_back(strl);
return elems;
@ -198,7 +182,7 @@ namespace yycc::string::op {
// start spliting
std::size_t previous = 0, current;
while ((current = strl.find(delimiter.c_str(), previous)) != NS_YYCC_STRING::u8string::npos) {
while ((current = strl.find(delimiter.c_str(), previous)) != std::u8string::npos) {
elems.emplace_back(strl.substr(previous, current - previous));
previous = current + delimiter.size();
}
@ -209,20 +193,20 @@ namespace yycc::string::op {
return elems;
}
std::vector<NS_YYCC_STRING::u8string> split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) {
// call split view
std::vector<std::u8string> split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter) {
// call split view
auto view_result = split(strl, _delimiter);
// copy string view result to string
std::vector<NS_YYCC_STRING::u8string> elems;
elems.reserve(view_result.size());
for (const auto& strl_view : view_result) {
elems.emplace_back(NS_YYCC_STRING::u8string(strl_view));
}
// return copied result
return elems;
}
// copy string view result to string
std::vector<std::u8string> elems;
elems.reserve(view_result.size());
for (const auto& strl_view : view_result) {
elems.emplace_back(std::u8string(strl_view));
}
// return copied result
return elems;
}
#pragma endregion
}
} // namespace yycc::string::op

View File

@ -1,65 +1,68 @@
#pragma once
#include <string>
#include <string_view>
#include <cstdarg>
#include <functional>
#include <vector>
#include "../string.hpp"
#define NS_YYCC_STRING ::yycc::string
#include <expected>
namespace yycc::string::op {
/**
* @brief Perform a string formatting operation.
* @param[out] strl
* The string container receiving the result.
* There is no guarantee that the content is not modified when function failed.
* @param[in] format The format string.
* @param[in] ... Argument list of format string.
* @return True if success, otherwise false.
*/
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...);
/**
* @brief Perform a string formatting operation.
* @param[out] strl
* The string container receiving the result.
* There is no guarantee that the content is not modified when function failed.
* @param[in] format The format string.
* @param[in] argptr Argument list of format string.
* @return True if success, otherwise false.
*/
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr);
/**
* @brief Perform a string formatting operation.
* @param[in] format The format string.
* @param[in] ... Argument list of format string.
* @return The formatting result. Empty string if error happened.
*/
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...);
/**
* @brief Perform a string formatting operation.
* @param[in] format The format string.
* @param[in] argptr Argument list of format string.
* @return The formatting result. Empty string if error happened.
*/
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr);
enum class FormatError {
NullFormat, ///< Given format string is nullptr.
NoDesiredSize, ///< Fail to fetch the expected size of result.
BadWrittenSize, ///< The written size is different with expected size.
};
/**
template<typename T>
using FormatResult = std::expected<T, FormatError>;
/**
* @brief Perform an UTF8 string formatting operation.
* @param[in] format The format string.
* @param[in] ... Argument list of format string.
* @return The formatted result, or the fail reason.
*/
FormatResult<std::u8string> printf(const char8_t* format, ...);
/**
* @brief Perform an UTF8 string formatting operation.
* @param[in] format The format string.
* @param[in] argptr Argument list of format string.
* @return The formatted result, or the fail reason.
*/
FormatResult<std::u8string> vprintf(const char8_t* format, va_list argptr);
/**
* @brief Perform an ordinary string formatting operation.
* @param[in] format The format string.
* @param[in] ... Argument list of format string.
* @return The formatted result, or the fail reason.
*/
FormatResult<std::string> printf(const char* format, ...);
/**
* @brief Perform an ordinary string formatting operation.
* @param[in] format The format string.
* @param[in] argptr Argument list of format string.
* @return The formatted result, or the fail reason.
*/
FormatResult<std::string> vprintf(const char* format, va_list argptr);
/**
* @brief Modify given string with all occurrences of substring \e old replaced by \e new.
* @param[in,out] strl The string for replacing
* @param[in] _from_strl The \e old string.
* @param[in] _to_strl The \e new string.
*/
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
/**
void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl);
/**
* @brief Return a copy with all occurrences of substring \e old replaced by \e new.
* @param[in] _strl The string for replacing
* @param[in] _from_strl The \e old string.
* @param[in] _to_strl The \e new string.
* @return The result of replacement.
*/
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl);
/**
/**
* @brief The data provider of general join function.
* @details
* For programmer using lambda to implement this function pointer:
@ -68,8 +71,8 @@ namespace yycc::string::op {
* \li Function return true to continue joining. otherwise return false to stop joining.
* The argument content assigned in the calling returning false is not included in join process.
*/
using JoinDataProvider = std::function<bool(NS_YYCC_STRING::u8string_view&)>;
/**
using JoinDataProvider = std::function<bool(std::u8string_view&)>;
/**
* @brief Universal join function.
* @details
* This function use function pointer as a general data provider interface,
@ -80,51 +83,56 @@ namespace yycc::string::op {
* @param[in] delimiter The delimiter used for joining.
* @return The result string of joining.
*/
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter);
/**
std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter);
/**
* @brief Specialized join function for standard library container.
* @tparam InputIt
* Must meet the requirements of LegacyInputIterator.
* It also can be dereferenced and then implicitly converted to NS_YYCC_STRING::u8string_view.
* It also can be dereferenced and then implicitly converted to std::u8string_view.
* @param[in] first The beginning of the range of elements to join.
* @param[in] last The terminal of the range of elements to join (exclusive).
* @param[in] delimiter The delimiter used for joining.
* @return The result string of joining.
*/
template<class InputIt>
NS_YYCC_STRING::u8string join(InputIt first, InputIt last, const NS_YYCC_STRING::u8string_view& delimiter) {
return join([&first, &last](NS_YYCC_STRING::u8string_view& view) -> bool {
// if we reach tail, return false to stop join process
if (first == last) return false;
// otherwise fetch data, inc iterator and return.
view = *first;
++first;
return true;
}, delimiter);
}
template<class InputIt>
std::u8string join(InputIt first, InputIt last, const std::u8string_view& delimiter) {
return join(
[&first, &last](std::u8string_view& view) -> bool {
// if we reach tail, return false to stop join process
if (first == last) return false;
// otherwise fetch data, inc iterator and return.
view = *first;
++first;
return true;
},
delimiter);
}
/**
/**
* @brief Convert given string to lowercase.
* @param[in,out] strl The string to be lowercase.
*/
void lower(NS_YYCC_STRING::u8string& strl);
/**
void lower(std::u8string& strl);
/**
* @brief Return a copy of the string converted to lowercase.
* @param[in] strl The string to be lowercase.
* @return The copy of the string converted to lowercase.
*/
NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl);
/**
std::u8string to_lower(const std::u8string_view& strl);
/**
* @brief Convert given string to uppercase.
* @param[in,out] strl The string to be uppercase.
*/
void upper(NS_YYCC_STRING::u8string& strl);
/**
void upper(std::u8string& strl);
/**
* @brief Return a copy of the string converted to uppercase.
* @param[in] strl The string to be uppercase.
* @return The copy of the string converted to uppercase.
*/
NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl);
std::u8string to_upper(const std::u8string_view& strl);
// TODO:
// Add strip, lstrip and rstrip functions.
/**
* @brief Split given string with specified delimiter as string view.
@ -136,10 +144,10 @@ namespace yycc::string::op {
* \par
* If given string or delimiter are empty,
* the result container will only contain 1 entry which is equal to given string.
* @see Split(const NS_YYCC_STRING::u8string_view&, const NS_YYCC_STRING::u8char*)
* @see Split(const std::u8string_view&, const char8_t*)
*/
std::vector<NS_YYCC_STRING::u8string_view> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
/**
std::vector<std::u8string_view> split(const std::u8string_view& strl, const std::u8string_view& _delimiter);
/**
* @brief Split given string with specified delimiter.
* @param[in] strl The string need to be splitting.
* @param[in] _delimiter The delimiter for splitting.
@ -149,9 +157,10 @@ namespace yycc::string::op {
* If given string or delimiter are empty,
* the result container will only contain 1 entry which is equal to given string.
*/
std::vector<NS_YYCC_STRING::u8string> split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
// undefined lazy_split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
std::vector<std::u8string> split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter);
}
// TODO:
// Add lazy_split(const std::u8string_view& strl, const std::u8string_view& _delimiter);
// Once we add it, we need redirect all split function into it.
#undef NS_YYCC_STRING
} // namespace yycc::string::op

View File

@ -1,33 +1,31 @@
#include "reinterpret.hpp"
#define NS_YYCC_STRING ::yycc::string
namespace yycc::string::reinterpret {
const NS_YYCC_STRING::u8char* as_utf8(const char* src) {
return reinterpret_cast<const NS_YYCC_STRING::u8char*>(src);
}
NS_YYCC_STRING::u8char* as_utf8(char* src) {
return reinterpret_cast<NS_YYCC_STRING::u8char*>(src);
}
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src) {
return NS_YYCC_STRING::u8string(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
}
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src) {
return NS_YYCC_STRING::u8string_view(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
}
const char8_t* as_utf8(const char* src) {
return reinterpret_cast<const char8_t*>(src);
}
char8_t* as_utf8(char* src) {
return reinterpret_cast<char8_t*>(src);
}
std::u8string as_utf8(const std::string_view& src) {
return std::u8string(reinterpret_cast<const char8_t*>(src.data()), src.size());
}
std::u8string_view as_utf8_view(const std::string_view& src) {
return std::u8string_view(reinterpret_cast<const char8_t*>(src.data()), src.size());
}
const char* as_ordinary(const NS_YYCC_STRING::u8char* src) {
return reinterpret_cast<const char*>(src);
}
char* as_ordinary(NS_YYCC_STRING::u8char* src) {
return reinterpret_cast<char*>(src);
}
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src) {
return std::string(reinterpret_cast<const char*>(src.data()), src.size());
}
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src) {
return std::string_view(reinterpret_cast<const char*>(src.data()), src.size());
}
const char* as_ordinary(const char8_t* src) {
return reinterpret_cast<const char*>(src);
}
char* as_ordinary(char8_t* src) {
return reinterpret_cast<char*>(src);
}
std::string as_ordinary(const std::u8string_view& src) {
return std::string(reinterpret_cast<const char*>(src.data()), src.size());
}
std::string_view as_ordinary_view(const std::u8string_view& src) {
return std::string_view(reinterpret_cast<const char*>(src.data()), src.size());
}
}
} // namespace yycc::string::reinterpret

View File

@ -1,7 +1,6 @@
#pragma once
#include "../string.hpp"
#define NS_YYCC_STRING ::yycc::string
#include <string>
#include <string_view>
/**
* @brief Provides utilities for reinterpretation between UTF-8 and ordinary string types.
@ -17,51 +16,49 @@ namespace yycc::string::reinterpret {
* @param src Source ordinary string
* @return Pointer to UTF-8 encoded string
*/
const NS_YYCC_STRING::u8char* as_utf8(const char* src);
const char8_t* as_utf8(const char* src);
/**
* @brief Reinterpret ordinary C-string as an UTF-8 string (non-const version).
* @param src Source ordinary string
* @return Pointer to UTF-8 encoded string
*/
NS_YYCC_STRING::u8char* as_utf8(char* src);
char8_t* as_utf8(char* src);
/**
* @brief Reinterpret ordinary string view to copied UTF-8 string.
* @param src Source ordinary string view
* @return UTF-8 encoded string
*/
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src);
std::u8string as_utf8(const std::string_view& src);
/**
* @brief Reinterpret ordinary string view to UTF-8 string view.
* @param src Source ordinary string view
* @return UTF-8 encoded string view
*/
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src);
std::u8string_view as_utf8_view(const std::string_view& src);
/**
* @brief Reinterpret UTF-8 C-string to ordinary string (const version).
* @param src Source UTF-8 string
* @return Pointer to ordinary string
*/
const char* as_ordinary(const NS_YYCC_STRING::u8char* src);
const char* as_ordinary(const char8_t* src);
/**
* @brief Reinterpret UTF-8 C-string to ordinary string (non-const version).
* @param src Source UTF-8 string
* @return Pointer to ordinary string
*/
char* as_ordinary(NS_YYCC_STRING::u8char* src);
char* as_ordinary(char8_t* src);
/**
* @brief Reinterpret UTF-8 string view to ordinary string.
* @param src Source UTF-8 string view
* @return Ordinary string
*/
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src);
std::string as_ordinary(const std::u8string_view& src);
/**
* @brief Reinterpret UTF-8 string view to ordinary string view
* @param src Source UTF-8 string view
* @return Ordinary string view
*/
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src);
std::string_view as_ordinary_view(const std::u8string_view& src);
}
#undef NS_YYCC_STRING

View File

@ -2,18 +2,8 @@
// Because this header is the part of wrapper, not a real header.
// #pragma once
#include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
// Define 2 macros to disallow Windows generate MIN and MAX macros
// which cause std::min and std::max can not function as normal.
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#endif
// YYC MARK:
// Since YYCC 2.0 version, we use CMake to handle Windows shitty macros,
// so we do not need declare WIN32_LEAN_AND_MEAN or NOMINMAX in there.
// But for keep the pair of this guard, we still keep this header file,
// although it do nothing.

View File

@ -4,7 +4,7 @@
#include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
// Windows also will generate following macros
// which may cause the function sign is different in Windows and other platforms.

View File

@ -1,16 +0,0 @@
#pragma once
#include "../macro/os_detector.hpp"
// If we are in Windows,
// we need add 2 macros to disable Windows shitty warnings and errors of
// depracted functions and not secure functions.
#if YYCC_OS == YYCC_OS_WINDOWS
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#if !defined(_CRT_NONSTDC_NO_DEPRECATE)
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif

View File

@ -34,20 +34,6 @@ PRIVATE
YYCCommonplace
GTest::gtest_main
)
# Setup C++ standard
target_compile_features(YYCCTestbench PUBLIC cxx_std_17)
set_target_properties(YYCCTestbench PROPERTIES CXX_EXTENSION OFF)
# Order Unicode charset for private using
target_compile_definitions(YYCCTestbench
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
)
# Order build as UTF-8 in MSVC
target_compile_options(YYCCTestbench
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
)
# Discover all test
include(GoogleTest)

View File

@ -167,7 +167,7 @@ namespace YYCCTestbench {
}
// check wstring convertion on windows
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
for (size_t i = 0u; i < count; ++i) {
// get item
const auto& u8str = c_UTF8TestStrTable[i];
@ -306,7 +306,7 @@ namespace YYCCTestbench {
}
static void DialogTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
YYCC::yycc_u8string ret;
std::vector<YYCC::yycc_u8string> rets;
@ -340,7 +340,7 @@ namespace YYCCTestbench {
}
static void ExceptionTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
YYCC::ExceptionHelper::Register([](const YYCC::yycc_u8string& log_path, const YYCC::yycc_u8string& coredump_path) -> void {
MessageBoxW(
@ -374,7 +374,7 @@ namespace YYCCTestbench {
}
static void WinFctTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
HMODULE test_current_module;
Assert((test_current_module = YYCC::WinFctHelper::GetCurrentModule()) != nullptr, YYCC_U8("YYCC::WinFctHelper::GetCurrentModule"));
@ -412,7 +412,7 @@ namespace YYCCTestbench {
}
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
std::wstring wdelimiter(1u, std::filesystem::path::preferred_separator);
YYCC::yycc_u8string delimiter(YYCC::EncodingHelper::WcharToUTF8(wdelimiter));
#else
@ -622,7 +622,7 @@ namespace YYCCTestbench {
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
}
}
#if YYCC_OS == YYCC_OS_WINDOWS
#if defined(YYCC_OS_WINDOWS)
{
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromWin32"));
auto result = YYCC::ArgParser::ArgumentList::CreateFromWin32();

View File

@ -0,0 +1,74 @@
/**
* \file
* This file is a template for Parse function testing.
*
* As you seen that there is 2 style Parse function locate in main namespace and Rust namespace respectively.
* Both of them share the exactly same test data sheet.
* So it is good idea to extract these common part and put them into a place, and include it in respectively testbench file.
* That what this file does.
*
* Before including this template file, you must make sure that:
* \li Have include <gtest/gtest.h>
* \li Have include <yycc/prelude/rust.hpp>
* \li Have define a macro named \c TEST_NS which indicate the testbench namespace passed to gtest.
* \li Have define a macro with syntax <TT>TEST_SUCCESS(type_t, value, string_value, ...)</TT>.
* This macro will be called for those success case. \c type_t is the generic type of Parse function.
* \c value is the expected value after parse and \c string_value is the string value to be parsed.
* Other arguments should be redirect to corresponding Parse function.
* \li Have define a macro with syntax <TT>TEST_FAIL(type_t, string_value, ...)</TT>.
* Opposite with \c TEST_SUCCESS, this macro is for those bad case testing.
* All arguments have the same meaning with \c TEST_SUCCESS.
*
*/
TEST(TEST_NS, Common) {
TEST_SUCCESS(i8, INT8_C(-61), "-61");
TEST_SUCCESS(u8, UINT8_C(200), "200");
TEST_SUCCESS(i16, INT16_C(6161), "6161");
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
TEST_SUCCESS(float, 1.0f, "1.0");
TEST_SUCCESS(double, 1.0, "1.0");
TEST_SUCCESS(bool, true, "true");
TEST_SUCCESS(bool, false, "false");
}
TEST(TEST_NS, Radix) {
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
TEST_SUCCESS(u32, UINT32_C(032), "032", 8);
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
}
TEST(TEST_NS, CaseInsensitive) {
TEST_SUCCESS(bool, true, "tRUE");
}
TEST(TEST_NS, Overflow) {
TEST_FAIL(i8, "6161");
TEST_FAIL(u8, "32800");
TEST_FAIL(i16, "61616161");
TEST_FAIL(u16, "4294967293");
TEST_FAIL(i32, "616161616161");
TEST_FAIL(u32, "9223372036854775807");
TEST_FAIL(i64, "616161616161616161616161");
TEST_FAIL(u64, "92233720368547758079223372036854775807");
TEST_FAIL(float, "1e40");
TEST_FAIL(double, "1e114514");
}
TEST(TEST_NS, BadRadix) {
TEST_FAIL(u32, "fghj", 16);
TEST_FAIL(u32, "099", 8);
TEST_FAIL(u32, "12345", 2);
}
TEST(TEST_NS, InvalidWords) {
TEST_FAIL(u32, "hello, world!");
TEST_FAIL(bool, "hello, world!");
}

View File

@ -0,0 +1,39 @@
/**
* \file
* This file is a template for Stringify function testing.
*
* Same as parse_template.hpp .
*
* Before including this template file, you must make sure that:
* \li Have include <gtest/gtest.h>
* \li Have include <yycc/prelude/rust.hpp>
* \li Have define a macro named \c TEST_NS which indicate the testbench namespace passed to gtest.
* \li Have define a macro with syntax <TT>TEST_SUCCESS(type_t, value, string_value, ...)</TT>.
* This macro will be called for those success case. \c type_t is the generic type of Stringify function.
* \c value is the value will be stringified and \c string_value is the expected string.
* Other arguments should be redirect to corresponding Stringify function.
*
*/
TEST(TEST_NS, Common) {
TEST_SUCCESS(i8, INT8_C(-61), "-61");
TEST_SUCCESS(u8, UINT8_C(200), "200");
TEST_SUCCESS(i16, INT16_C(6161), "6161");
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
TEST_SUCCESS(float, 1.0f, "1.0", std::chars_format::fixed, 1);
TEST_SUCCESS(double, 1.0, "1.0", std::chars_format::fixed, 1);
TEST_SUCCESS(bool, true, "true");
TEST_SUCCESS(bool, false, "false");
}
TEST(TEST_NS, Radix) {
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
TEST_SUCCESS(u32, UINT32_C(032), "32", 8);
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
}

View File

@ -11,6 +11,8 @@ namespace yycctest::num::parse {
// These 2 test macros build string container via given string.
// Check `try_parse` first, and then check `parse`.
#define TEST_NS NumParse
#define TEST_SUCCESS(type_t, value, string_value, ...) \
{ \
u8string cache_string(YYCC_U8(string_value)); \
@ -28,56 +30,6 @@ namespace yycctest::num::parse {
EXPECT_ANY_THROW(PARSE::parse<type_t>(cache_string, ##__VA_ARGS__)); \
}
TEST(NumParse, Common) {
TEST_SUCCESS(i8, INT8_C(-61), "-61");
TEST_SUCCESS(u8, UINT8_C(200), "200");
TEST_SUCCESS(i16, INT16_C(6161), "6161");
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
#include "../../shared/parse_template.hpp"
TEST_SUCCESS(float, 1.0f, "1.0");
TEST_SUCCESS(double, 1.0, "1.0");
TEST_SUCCESS(bool, true, "true");
TEST_SUCCESS(bool, false, "false");
}
TEST(NumParse, Radix) {
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
TEST_SUCCESS(u32, UINT32_C(032), "032", 8);
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
}
TEST(NumParse, CaseInsensitive) {
TEST_SUCCESS(bool, true, "tRUE");
}
TEST(NumParse, Overflow) {
TEST_FAIL(i8, "6161");
TEST_FAIL(u8, "32800");
TEST_FAIL(i16, "61616161");
TEST_FAIL(u16, "4294967293");
TEST_FAIL(i32, "616161616161");
TEST_FAIL(u32, "9223372036854775807");
TEST_FAIL(i64, "616161616161616161616161");
TEST_FAIL(u64, "92233720368547758079223372036854775807");
TEST_FAIL(float, "1e40");
TEST_FAIL(double, "1e114514");
}
TEST(NumParse, BadRadix) {
TEST_FAIL(u32, "fghj", 16);
TEST_FAIL(u32, "099", 8);
TEST_FAIL(u32, "12345", 2);
}
TEST(NumParse, InvalidWords) {
TEST_FAIL(u32, "hello, world!");
TEST_FAIL(bool, "hello, world!");
}
} // namespace yycctest::string::parse
} // namespace yycctest::num::parse

View File

@ -8,6 +8,8 @@
namespace yycctest::num::stringify {
#define TEST_NS NumStringify
#define TEST_SUCCESS(type_t, value, string_value, ...) \
{ \
type_t cache = value; \
@ -15,27 +17,6 @@ namespace yycctest::num::stringify {
EXPECT_EQ(ret, YYCC_U8(string_value)); \
}
TEST(NumStringify, Common) {
TEST_SUCCESS(i8, INT8_C(-61), "-61");
TEST_SUCCESS(u8, UINT8_C(200), "200");
TEST_SUCCESS(i16, INT16_C(6161), "6161");
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
TEST_SUCCESS(float, 1.0f, "1.0", std::chars_format::fixed, 1);
TEST_SUCCESS(double, 1.0, "1.0", std::chars_format::fixed, 1);
TEST_SUCCESS(bool, true, "true");
TEST_SUCCESS(bool, false, "false");
}
TEST(NumStringify, Radix) {
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
TEST_SUCCESS(u32, UINT32_C(032), "32", 8);
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
}
#include "../../shared/stringify_template.hpp"
} // namespace yycctest::string::stringify

View File

@ -6,14 +6,12 @@
#define PARSE ::yycc::rust::num::parse
namespace yycctest::rust::parse {
namespace yycctest::rust::num::parse {
// We only want to test it if C++ support it.
#if defined(YYCC_CPPFEAT_EXPECTED)
// This namespace is just a wrapper for legacy "parse" module.
// So the test is just a copy of original implementation.
// Please update this if original test was updated.
#define TEST_NS RustNumParse
#define TEST_SUCCESS(type_t, expected_value, string_value, ...) \
{ \
@ -30,57 +28,7 @@ namespace yycctest::rust::parse {
EXPECT_FALSE(rv.has_value()); \
}
TEST(RustNumParse, Common) {
TEST_SUCCESS(i8, INT8_C(-61), "-61");
TEST_SUCCESS(u8, UINT8_C(200), "200");
TEST_SUCCESS(i16, INT16_C(6161), "6161");
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
TEST_SUCCESS(float, 1.0f, "1.0");
TEST_SUCCESS(double, 1.0, "1.0");
TEST_SUCCESS(bool, true, "true");
TEST_SUCCESS(bool, false, "false");
}
TEST(RustNumParse, Radix) {
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
TEST_SUCCESS(u32, UINT32_C(032), "032", 8);
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
}
TEST(RustNumParse, CaseInsensitive) {
TEST_SUCCESS(bool, true, "tRUE");
}
TEST(RustNumParse, Overflow) {
TEST_FAIL(i8, "6161");
TEST_FAIL(u8, "32800");
TEST_FAIL(i16, "61616161");
TEST_FAIL(u16, "4294967293");
TEST_FAIL(i32, "616161616161");
TEST_FAIL(u32, "9223372036854775807");
TEST_FAIL(i64, "616161616161616161616161");
TEST_FAIL(u64, "92233720368547758079223372036854775807");
TEST_FAIL(float, "1e40");
TEST_FAIL(double, "1e114514");
}
TEST(RustNumParse, BadRadix) {
TEST_FAIL(u32, "fghj", 16);
TEST_FAIL(u32, "099", 8);
TEST_FAIL(u32, "12345", 2);
}
TEST(RustNumParse, InvalidWords) {
TEST_FAIL(u32, "hello, world!");
TEST_FAIL(bool, "hello, world!");
}
#include "../../../shared/parse_template.hpp"
#endif

View File

@ -4,11 +4,19 @@
#include <yycc/prelude/rust.hpp>
#define STRINGIFY ::yycc::string::stringify
#define STRINGIFY ::yycc::rust::num::stringify
namespace yycctest::rust::stringify {
namespace yycctest::rust::num::stringify {
// There is not testbench for this
// because it just a map to original implementation without any modification.
#define TEST_NS RustNumStringify
#define TEST_SUCCESS(type_t, value, string_value, ...) \
{ \
type_t cache = value; \
u8string ret = STRINGIFY::stringify<type_t>(cache, ##__VA_ARGS__); \
EXPECT_EQ(ret, YYCC_U8(string_value)); \
}
#include "../../../shared/stringify_template.hpp"
}