Compare commits
11 Commits
e42a3b6e58
...
b79df0c65e
Author | SHA1 | Date | |
---|---|---|---|
b79df0c65e | |||
4f0b3d19d1 | |||
f014e54604 | |||
821a592f02 | |||
6043609709 | |||
53e8a77f47 | |||
6d44c7605b | |||
c2f6e29c36 | |||
c102964703 | |||
3605151caf | |||
fa52d7416f |
@ -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
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
# -------------------- Output --------------------
|
||||
out/
|
||||
src/YYCC/YYCCVersion.hpp
|
||||
src/yycc/version.hpp
|
||||
CMakeSettings.json
|
||||
|
||||
# -------------------- VSCode --------------------
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
215
script/.gitignore
vendored
@ -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__/
|
||||
|
@ -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
2
script/pycodec/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Exclude result
|
||||
*.cpp
|
63
script/pycodec/conv_encoding_table.py
Normal file
63
script/pycodec/conv_encoding_table.py
Normal 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)
|
98
script/pycodec/encoding_table.csv
Normal file
98
script/pycodec/encoding_table.csv
Normal 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
|
|
7
script/pyproject.toml
Normal file
7
script/pyproject.toml
Normal 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
74
script/uv.lock
generated
Normal 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" }]
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "COMHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
namespace YYCC::COMHelper {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "DialogHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#include "EncodingHelper.hpp"
|
||||
#include "StringHelper.hpp"
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#include "ExceptionHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#include "WinFctHelper.hpp"
|
||||
#include "ConsoleHelper.hpp"
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "WinFctHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#include "EncodingHelper.hpp"
|
||||
#include "COMHelper.hpp"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -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
|
||||
|
10
src/yycc.hpp
10
src/yycc.hpp
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
446
src/yycc/encoding/pycodec.cpp
Normal file
446
src/yycc/encoding/pycodec.cpp
Normal 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
|
202
src/yycc/encoding/pycodec.hpp
Normal file
202
src/yycc/encoding/pycodec.hpp
Normal 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
|
118
src/yycc/encoding/stlcvt.cpp
Normal file
118
src/yycc/encoding/stlcvt.cpp
Normal 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
|
43
src/yycc/encoding/stlcvt.hpp
Normal file
43
src/yycc/encoding/stlcvt.hpp
Normal 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);
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
30
src/yycc/macro/compiler_detector.hpp
Normal file
30
src/yycc/macro/compiler_detector.hpp
Normal 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
|
28
src/yycc/macro/endian_detector.hpp
Normal file
28
src/yycc/macro/endian_detector.hpp
Normal 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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -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;
|
@ -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
|
@ -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
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user