diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..e388b2b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,39 @@ +Checks: "*,\ + -altera-struct-pack-align,\ + -altera-unroll-loops,\ + -altera-id-dependent-backward-branch,\ + -llvmlibc-callee-namespace,\ + -llvmlibc-restrict-system-libc-headers,\ + -llvmlibc-implementation-in-namespace,\ + -llvmlibc-inline-function-decl,\ + -llvm-else-after-return,\ + -llvm-header-guard,\ + -llvm-include-order,\ + -bugprone-branch-clone,\ + -bugprone-suspicious-include,\ + -bugprone-easily-swappable-parameters,\ + -modernize-use-trailing-return-type,\ + -hicpp-special-member-functions,\ + -google-runtime-references,\ + -fuchsia-overloaded-operator,\ + -fuchsia-default-arguments,\ + -google-readability-todo,\ + -google-global-names-in-headers,\ + -readability-redundant-access-specifiers,\ + -readability-else-after-return,\ + -readability-implicit-bool-conversion,\ + -readability-use-anyofallof,\ + -readability-identifier-length,\ + -performance-inefficient-string-concatenation,\ + -performance-unnecessary-value-param,\ + -fuchsia-default-arguments-declarations,\ + -fuchsia-trailing-return,\ + -fuchsia-multiple-inheritance,\ + -fuchsia-default-arguments-calls,\ + -misc-non-private-member-variables-in-classes,\ + -misc-no-recursion,\ + -misc-include-cleaner,\ + -cppcoreguidelines-special-member-functions,\ + -cppcoreguidelines-prefer-member-initializer,\ + -cppcoreguidelines-avoid-const-or-ref-data-members,\ + -cppcoreguidelines-non-private-member-variables-in-classes" \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9f280b7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,29 @@ +# Git +.git +.gitignore +.github + +# Windows specific +*.ps1 + + +# Local build/utility folders +.vscode +.vs +*.vcxproj.user +*.pyc +*.pyd + +**/CMakeUserPresets.json +output +packages +**/build +**/venv +**/pyconcept/import +**/egg-info + + +# Specific items +docker-compose.yml +rslang/src/RSParserImpl.output +rslang/src/RSParserImpl.gv \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4df4cc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +~* +.vs +*.vcxproj.user +*.pch.tmp +*.clang.pch +*.pyc +*.pyd + +packages +build +output +venv/ +CMakeUserPresets.json +pyconcept/import/ +*egg-info + +ccl/rslang/src/RSParserImpl.output +ccl/rslang/src/RSParserImpl.gv \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2c7548e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "cSpell.words": [ + "DCMAKE", + "debool", + "Decartian", + "defexpr", + "gtest", + "MSVC", + "nlohmann", + "noteq", + "notsubset", + "pybind", + "pyconcept", + "rslang", + "symmdiff" + ] +} diff --git a/CCL-Full.sln b/CCL-Full.sln new file mode 100644 index 0000000..dab9dd3 --- /dev/null +++ b/CCL-Full.sln @@ -0,0 +1,152 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConceptCoreLibrary", "ccl\core\ConceptLibrary.vcxproj", "{B0ABA27B-9D39-4B48-9977-AFF20925B309}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RSlang", "ccl\rslang\RSlang.vcxproj", "{A8529C63-42F5-43E6-97B8-2EC83F23E1F9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RSlangTest", "ccl\rslang\test\rslTest.vcxproj", "{32469CE1-303B-4DB4-8E03-B7EBED5851EB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclGraph", "ccl\cclGraph\cclGraph.vcxproj", "{7E1D5338-F819-4C96-B461-9EAAB8D02E1D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclGraphTest", "ccl\cclGraph\test\cclGraphTest.vcxproj", "{5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclLang", "ccl\cclLang\cclLang.vcxproj", "{76B03803-56CC-47C2-A8F0-2241FCAF2898}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclLangTest", "ccl\cclLang\test\cclLangTest.vcxproj", "{4754356B-DC01-4564-A035-270FFB72F6A0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{FB8E3011-BB07-4F6E-B2C7-A0A183BC5000}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConceptCoreDLL", "coredll\ConceptCoreDLL.vcxproj", "{6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclTest", "ccl\core\test\cclTest.vcxproj", "{F87048D4-952A-460E-96E8-1E2E1EAE34FC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ccdTest", "coredll\test\ccdTest.vcxproj", "{6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cclCommonsTest", "ccl\cclCommons\test\cclCommonsTest.vcxproj", "{53A380CF-B599-4170-89B1-642F1C3772E1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyconcept", "pyconcept\pyconcept.vcxproj", "{692F2E27-1749-4A3C-9543-C4101E7B8E49}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Debug|x64.ActiveCfg = Debug|x64 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Debug|x64.Build.0 = Debug|x64 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Debug|x86.ActiveCfg = Debug|Win32 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Debug|x86.Build.0 = Debug|Win32 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Release|x64.ActiveCfg = Release|x64 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Release|x64.Build.0 = Release|x64 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Release|x86.ActiveCfg = Release|Win32 + {B0ABA27B-9D39-4B48-9977-AFF20925B309}.Release|x86.Build.0 = Release|Win32 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Debug|x64.ActiveCfg = Debug|x64 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Debug|x64.Build.0 = Debug|x64 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Debug|x86.ActiveCfg = Debug|Win32 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Debug|x86.Build.0 = Debug|Win32 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Release|x64.ActiveCfg = Release|x64 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Release|x64.Build.0 = Release|x64 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Release|x86.ActiveCfg = Release|Win32 + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9}.Release|x86.Build.0 = Release|Win32 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Debug|x64.ActiveCfg = Debug|x64 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Debug|x64.Build.0 = Debug|x64 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Debug|x86.ActiveCfg = Debug|Win32 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Debug|x86.Build.0 = Debug|Win32 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Release|x64.ActiveCfg = Release|x64 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Release|x64.Build.0 = Release|x64 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Release|x86.ActiveCfg = Release|Win32 + {32469CE1-303B-4DB4-8E03-B7EBED5851EB}.Release|x86.Build.0 = Release|Win32 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Debug|x64.ActiveCfg = Debug|x64 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Debug|x64.Build.0 = Debug|x64 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Debug|x86.ActiveCfg = Debug|Win32 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Debug|x86.Build.0 = Debug|Win32 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Release|x64.ActiveCfg = Release|x64 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Release|x64.Build.0 = Release|x64 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Release|x86.ActiveCfg = Release|Win32 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D}.Release|x86.Build.0 = Release|Win32 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Debug|x64.ActiveCfg = Debug|x64 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Debug|x64.Build.0 = Debug|x64 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Debug|x86.ActiveCfg = Debug|Win32 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Debug|x86.Build.0 = Debug|Win32 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Release|x64.ActiveCfg = Release|x64 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Release|x64.Build.0 = Release|x64 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Release|x86.ActiveCfg = Release|Win32 + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}.Release|x86.Build.0 = Release|Win32 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Debug|x64.ActiveCfg = Debug|x64 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Debug|x64.Build.0 = Debug|x64 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Debug|x86.ActiveCfg = Debug|Win32 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Debug|x86.Build.0 = Debug|Win32 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Release|x64.ActiveCfg = Release|x64 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Release|x64.Build.0 = Release|x64 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Release|x86.ActiveCfg = Release|Win32 + {76B03803-56CC-47C2-A8F0-2241FCAF2898}.Release|x86.Build.0 = Release|Win32 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Debug|x64.ActiveCfg = Debug|x64 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Debug|x64.Build.0 = Debug|x64 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Debug|x86.ActiveCfg = Debug|Win32 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Debug|x86.Build.0 = Debug|Win32 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Release|x64.ActiveCfg = Release|x64 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Release|x64.Build.0 = Release|x64 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Release|x86.ActiveCfg = Release|Win32 + {4754356B-DC01-4564-A035-270FFB72F6A0}.Release|x86.Build.0 = Release|Win32 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Debug|x64.ActiveCfg = Debug|x64 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Debug|x64.Build.0 = Debug|x64 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Debug|x86.ActiveCfg = Debug|Win32 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Debug|x86.Build.0 = Debug|Win32 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Release|x64.ActiveCfg = Release|x64 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Release|x64.Build.0 = Release|x64 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Release|x86.ActiveCfg = Release|Win32 + {6FDADD78-2FC1-4DBD-A2C4-B2EF35025AC0}.Release|x86.Build.0 = Release|Win32 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Debug|x64.ActiveCfg = Debug|x64 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Debug|x64.Build.0 = Debug|x64 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Debug|x86.ActiveCfg = Debug|Win32 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Debug|x86.Build.0 = Debug|Win32 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Release|x64.ActiveCfg = Release|x64 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Release|x64.Build.0 = Release|x64 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Release|x86.ActiveCfg = Release|Win32 + {F87048D4-952A-460E-96E8-1E2E1EAE34FC}.Release|x86.Build.0 = Release|Win32 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Debug|x64.ActiveCfg = Debug|x64 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Debug|x64.Build.0 = Debug|x64 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Debug|x86.ActiveCfg = Debug|Win32 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Debug|x86.Build.0 = Debug|Win32 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Release|x64.ActiveCfg = Release|x64 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Release|x64.Build.0 = Release|x64 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Release|x86.ActiveCfg = Release|Win32 + {6BDE1298-8F16-4275-BA8A-F6CC54CB9B9D}.Release|x86.Build.0 = Release|Win32 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Debug|x64.ActiveCfg = Debug|x64 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Debug|x64.Build.0 = Debug|x64 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Debug|x86.ActiveCfg = Debug|Win32 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Debug|x86.Build.0 = Debug|Win32 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Release|x64.ActiveCfg = Release|x64 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Release|x64.Build.0 = Release|x64 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Release|x86.ActiveCfg = Release|Win32 + {53A380CF-B599-4170-89B1-642F1C3772E1}.Release|x86.Build.0 = Release|Win32 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Debug|x64.ActiveCfg = Debug|x64 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Debug|x64.Build.0 = Debug|x64 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Debug|x86.ActiveCfg = Debug|Win32 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Debug|x86.Build.0 = Debug|Win32 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Release|x64.ActiveCfg = Release|x64 + {692F2E27-1749-4A3C-9543-C4101E7B8E49}.Release|x86.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B0ABA27B-9D39-4B48-9977-AFF20925B309} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {A8529C63-42F5-43E6-97B8-2EC83F23E1F9} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {32469CE1-303B-4DB4-8E03-B7EBED5851EB} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {76B03803-56CC-47C2-A8F0-2241FCAF2898} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {4754356B-DC01-4564-A035-270FFB72F6A0} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {F87048D4-952A-460E-96E8-1E2E1EAE34FC} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + {53A380CF-B599-4170-89B1-642F1C3772E1} = {FB8E3011-BB07-4F6E-B2C7-A0A183BC5000} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F00AAF54-A857-4895-B4D8-1A09BC7CAD50} + EndGlobalSection +EndGlobal diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5a79907 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,103 @@ +# ubunutu is the base image +FROM ubuntu:jammy as cpp-builder +LABEL version="1.0" +LABEL maintainer="IRBorisov iborisov@acconcept.ru" +LABEL description="Linux build environment" + +ARG LINUX_FLAVOR=ubuntu +ARG LINUX_DISTR=jammy +ARG DEBIAN_FRONTEND=noninteractive + +# Install standard packages +RUN apt-get update -qq && \ + apt-get full-upgrade -y && \ + apt-get install -y --no-install-recommends \ + nano \ + wget \ + curl \ + tar \ + unzip \ + git \ + software-properties-common \ + build-essential \ + gpg-agent && \ + rm -rf /var/lib/apt/lists/* + +# Install Python and Conan +RUN add-apt-repository -y ppa:deadsnakes/ppa && \ + apt-get update -qq && \ + apt-get install -y --no-install-recommends \ + python3.12 \ + python3.12-venv \ + python3.12-dev && \ + curl -sS https://bootstrap.pypa.io/get-pip.py | python3.12 && \ + python3.12 -m pip install --upgrade pip setuptools && \ + python3.12 -m pip install conan && \ + rm -rf /var/lib/apt/lists/* + +# Add GCC compiler +ARG GCC_VER="13" +RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test && \ + apt-get update -qq && \ + apt-get install -y --no-install-recommends \ + gcc-${GCC_VER} \ + g++-${GCC_VER} && \ + update-alternatives --install /usr/bin/gcc gcc $(which gcc-${GCC_VER}) 100 && \ + update-alternatives --install /usr/bin/g++ g++ $(which g++-${GCC_VER}) 100 && \ + rm -rf /var/lib/apt/lists/* + +# Add Clang compiler +ARG LLVM_VER="18" +RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 2>/dev/null +RUN add-apt-repository -y "deb http://apt.llvm.org/${LINUX_DISTR}/ llvm-toolchain-${LINUX_DISTR}-${LLVM_VER} main" && \ + apt-get update -qq && \ + apt-get install -y --no-install-recommends \ + clang-${LLVM_VER} \ + clang-tools-${LLVM_VER} \ + clangd-${LLVM_VER} \ + lld-${LLVM_VER} \ + lldb-${LLVM_VER} \ + llvm-${LLVM_VER} \ + llvm-${LLVM_VER}-dev \ + llvm-${LLVM_VER}-runtime \ + libc++-${LLVM_VER}-dev \ + libc++abi-${LLVM_VER}-dev \ + libclang-${LLVM_VER}-dev \ + libclang-common-${LLVM_VER}-dev \ + libfuzzer-${LLVM_VER}-dev \ + clang-tidy-${LLVM_VER} && \ + update-alternatives --install /usr/bin/clang clang $(which clang-${LLVM_VER}) 100 && \ + update-alternatives --install /usr/bin/clang++ clang++ $(which clang++-${LLVM_VER}) 100 && \ + update-alternatives --install /usr/bin/clang-tidy clang-tidy $(which clang-tidy-${LLVM_VER}) 1 && \ + rm -rf /var/lib/apt/lists/* + +# Add CMake +RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \ + | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null && \ + apt-add-repository "deb https://apt.kitware.com/${LINUX_FLAVOR}/ ${LINUX_DISTR} main" && \ + apt-get update -qq && \ + apt-get install -y --no-install-recommends \ + cmake && \ + rm -rf /var/lib/apt/lists/* + +# Cleanup cached apt data we don't need anymore +RUN apt-get autoclean -y && \ + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# ====================== END OF CPP-Python environment ================== + +FROM cpp-builder as CCL +ARG CMAKE_BUILD_TYPE="Release" + +# Choose between clang/clang++ or gcc/g++ +ENV CC="gcc" +ENV CXX="g++" + +ENV BUILD_HOME=/home +WORKDIR $BUILD_HOME + +COPY . /home + +ENTRYPOINT ["sh", "/home/entrypoint.sh"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 5acb69f..7bd0192 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Ivan +Copyright (c) 2024 CIHT CONCEPT, IRBorisov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7b84fa --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# 🏛️ ConceptCore + +C++ library for manipulating concepts in formal language of advanced set theory + +## 🌲 Structure + +- ccl - ConceptCoreLibrary static C++ library +- coredll - ConceptCoreDLL binary for Windows embedding +- pyconcept - Python wrapper for some core RSLanguage and parsing functions + +## 📦 Project build + +Use Dockerfile to setup Clang / GCC build for Ubuntu development. +Use VS Solution for Windows development. +Use ccl/CMakeLists.txt for other platforms. + +Windows development requires Bison installed and Visual Studio 2022+. +After changing grammar / syntax you can rebuild lexers and parser using scripts in 'scripts' folder. + +If you want to only build pyconcept: + +- Build CCL-Full.sln in Release mode. +- Make sure you have Python installed and executable path is present in environment variables. +- Run pyconcept\script\Build.ps1. Answer 'A' if execution policy prompts for input +- pyconcept wheel will be deposited in output\py folder + +## 💝 Acknowledgements + +This project is based on multiple projects and works listed below. If you notice any problems with licensing or missing acknowledgements please inform repository maintainer. + +- [Re-flex](https://github.com/Genivia/RE-flex) provides clear way to generate lexical analyzers for ASCII and Unicode syntax variations +- [Bison](https://www.gnu.org/software/bison/) is used to generate language parser +- [nlohmann-json](https://github.com/nlohmann/json) is embedded as C++ JSON parser for conceptual schema persistence and high level JSON strings API +- [Clang-tidy](https://clang.llvm.org/extra/clang-tidy/) along with Visual Studio analyzer are used for C++ static code analysis +- [pybind11](https://github.com/pybind/pybind11) is used to generate Python module wrapper for C++ integration +- [CMake](https://cmake.org/) provides C++ projects build toolchain +- [conan](https://conan.io/) and NuGet are used to manage package dependencies +- Docker container is used to provide consistent build environment for Linux builds +- Microsoft Visual Studio 2022 and Visual Studio Code are used as IDE's and build environments for Windows builds diff --git a/ccl/CMakeLists.txt b/ccl/CMakeLists.txt new file mode 100644 index 0000000..2946cf5 --- /dev/null +++ b/ccl/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 3.23) + +project (ConceptCoreLibrary VERSION 1.2.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +## +## Project options +## +option(CC_BuildTests "Include tests executable" TRUE) +option(CC_UseSanitizers "Use sanitizers" FALSE) + +## Compiler options +include(cmake/CXXTargets.cmake) + +## Import internal targets +add_subdirectory(cclCommons) +add_subdirectory(cclGraph) +add_subdirectory(cclLang) +add_subdirectory(rslang) + +## +## Project Setup +## +add_library(${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + DEBUG_POSTFIX d + POSITION_INDEPENDENT_CODE ON +) + +target_sources(${PROJECT_NAME} + PRIVATE + core/unity/CCL.cpp +) +target_include_directories(${PROJECT_NAME} + PUBLIC + cclCommons/include + cclGraph/include + cclLang/include + rslang/include + core/include + PRIVATE + core/import/include + core/header +) +target_link_libraries(${PROJECT_NAME} + INTERFACE + RSLang + cclLang + cclGraph + PRIVATE + ccl_CXXwarnings + ccl_CXXoptions +) + +if(MSVC) + if (CMAKE_BUILD_TYPE EQUAL "DEBUG") + set(LIB_SUFFIX d) + else() + set(LIB_SUFFIX "") + endif () + + set_target_properties(${PROJECT_NAME} + PROPERTIES + COMPILE_PDB_NAME ${PROJECT_NAME}${LIB_SUFFIX} + ) + + get_target_property(output_dir ${PROJECT_NAME} BINARY_DIR) + install(FILES ${output_dir}/$/${PROJECT_NAME}${LIB_SUFFIX}.pdb DESTINATION lib) +endif() + +install(TARGETS ${PROJECT_NAME} + ARCHIVE + DESTINATION lib + LIBRARY + DESTINATION lib + INCLUDES + DESTINATION include +) +install(DIRECTORY core/include/ DESTINATION include) + +if(CC_BuildTests) + enable_testing() + add_subdirectory("core/test") +endif() \ No newline at end of file diff --git a/ccl/cclCommons/CMakeLists.txt b/ccl/cclCommons/CMakeLists.txt new file mode 100644 index 0000000..2e0f9a3 --- /dev/null +++ b/ccl/cclCommons/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.23) + +project (cclCommons VERSION 1.2.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +## +## Project options +## +option(CC_BuildTests "Include tests executable" TRUE) +option(CC_UseSanitizers "Use sanitizers" FALSE) + +## Compiler options +include(../cmake/CXXTargets.cmake) + +## +## Project Setup +## +install(DIRECTORY include/ DESTINATION include) + +if(CC_BuildTests) + enable_testing() + add_subdirectory("test") +endif() \ No newline at end of file diff --git a/ccl/cclCommons/conanfile.txt b/ccl/cclCommons/conanfile.txt new file mode 100644 index 0000000..a345ddf --- /dev/null +++ b/ccl/cclCommons/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +gtest/1.14.0 + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout \ No newline at end of file diff --git a/ccl/cclCommons/include/ccl/Strings.hpp b/ccl/cclCommons/include/ccl/Strings.hpp new file mode 100644 index 0000000..34275ca --- /dev/null +++ b/ccl/cclCommons/include/ccl/Strings.hpp @@ -0,0 +1,337 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ccl { + +inline std::string operator""_c17(const char8_t* input, size_t /*size*/) { +// TODO: C++20 use constexpr version from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1423r0.html + return std::string{ reinterpret_cast(input) }; +} + +template +std::u8string to_u8string(const T& obj) { + auto str = std::to_string(obj); + return std::u8string{ begin(str), end(str) }; // TODO: do not copy! +} + +template<> +inline std::u8string to_u8string(const std::string& obj) { + return std::u8string{ begin(obj), end(obj) }; +} + +inline std::string u8to_string(const std::u8string& obj) { + return std::string{ begin(obj), end(obj) }; +} + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26481 ) // disable pointer arithmetic warning - it is ok to use it on string_view +#endif + +//! Split string_view by specific symbol +inline std::vector SplitBySymbol(std::string_view text, char delim = ',') { + std::vector items{}; + int32_t leftComma = 0; + int32_t rightComma = -1; + int32_t index = -1; + for (const auto& symbol : text) { + ++index; + if (symbol != delim) { + continue; + } + leftComma = rightComma; + rightComma = index; + const auto start = leftComma + 1; + const auto length = rightComma - start; + items.emplace_back(text.data() + start, length); + } + items.emplace_back(text.data() + rightComma + 1, static_cast(text.size()) - rightComma - 1); + return items; +} + +//! Trim whitespace +inline std::string_view TrimWhitespace(std::string_view text) { + if (empty(text)) { + return text; + } + size_t start = 0U; + size_t end = text.length() - 1; + while (std::isspace(text.at(start)) && ++start < end) {} + while (std::isspace(text.at(end)) && end != 0 && --end >= start) {} + const size_t length = start > end ? 0 : end - start + 1; + return { text.data() + start, length }; +} + +//! Check if text is integer (including negative integers) +inline bool IsInteger(std::string_view text) { + if (empty(text)) { + return false; + } + size_t pos = 0; + if (text.at(pos) == '-') { + ++pos; + if (text.length() == 1) { + return false; + } + } + while (pos < text.length()) { + if (!std::isdigit(text.at(pos))) { + return false; + } + ++pos; + } + return true; +} + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +//! String position corresponds to CodePoint position +/* + Warning: codepoint position != array index in char* UTF8 string +*/ +using StrPos = int32_t; + +//! String range based on interval algebra +/* + Warning: lightweight class, doesnt provide any bounds checks! + For reference see https://en.wikipedia.org/wiki/Allen%27s_interval_algebra + Pre: start <= finish +*/ +struct StrRange { + constexpr StrRange() noexcept = default; + explicit constexpr StrRange(StrPos start, StrPos end) noexcept + : start{ start }, finish{ end } {} + + [[nodiscard]] static constexpr StrRange FromLength(StrPos start, StrPos len) noexcept { + return StrRange{ start, start + len }; + } + + StrPos start{ 0 }; + StrPos finish{ 0 }; + + [[nodiscard]] constexpr StrPos length() const noexcept { return finish - start; } + [[nodiscard]] constexpr bool empty() const noexcept { return finish == start; } + + [[nodiscard]] constexpr bool operator==(const StrRange& rhs) const noexcept { + return start == rhs.start && finish == rhs.finish; + } + [[nodiscard]] constexpr bool operator!=(const StrRange& rhs) const noexcept { + return !(*this == rhs); + } + [[nodiscard]] constexpr bool Contains(const StrPos pos) const noexcept { + return start <= pos && finish > pos; + } + [[nodiscard]] constexpr bool Contains(const StrRange& rhs) const noexcept { + if (std::empty(rhs)) { + return Contains(rhs.finish); + } else { + return start <= rhs.start && finish >= rhs.finish; + } + } + [[nodiscard]] constexpr bool SharesBorder(const StrRange& rhs) const noexcept { + return Meets(rhs) || rhs.Meets(*this); + } + + [[nodiscard]] constexpr bool IsBefore(const StrRange& rhs) const noexcept { + return finish < rhs.start; + } + [[nodiscard]] constexpr bool IsAfter(const StrRange& rhs) const noexcept { + return start > rhs.finish; + } + [[nodiscard]] constexpr bool Meets(const StrRange& rhs) const noexcept { + return finish == rhs.start; + } + [[nodiscard]] constexpr bool Overlaps(const StrRange& rhs) const noexcept { + if (start == rhs.start) { + return true; + } else if (start < rhs.start) { + return finish > rhs.start; + } else { + return rhs.finish > start; + } + } + [[nodiscard]] constexpr bool Starts(const StrRange& rhs) const noexcept { + return start == rhs.start && finish < rhs.finish; + } + [[nodiscard]] constexpr bool Finishes(const StrRange& rhs) const noexcept { + return finish == rhs.finish && start > rhs.start; + } + [[nodiscard]] constexpr bool IsDuring(const StrRange& rhs) const noexcept { + return start > rhs.start && finish < rhs.finish; + } + + //! Pre: assert(ammount >= 0) + constexpr StrRange& SetLength(StrPos ammount) noexcept { + finish = start + ammount; + return *this; + } + constexpr StrRange& Shift(StrPos ammount) noexcept { + start = start + ammount; + finish = finish + ammount; + return *this; + } + constexpr StrRange& CollapseEnd() noexcept { + start = finish; + return *this; + } + constexpr StrRange& CollapseStart() noexcept { + finish = start; + return *this; + } + + [[nodiscard]] constexpr std::optional Intersect(const StrRange& rhs) const { + if (IsBefore(rhs) || IsAfter(rhs)) { + return std::nullopt; + } else { + return StrRange{ std::max(start, rhs.start), std::min(finish, rhs.finish) }; + } + } + + static constexpr StrRange Merge(const std::vector& base) { + if (std::empty(base)) { + return StrRange{}; + } else { + return std::accumulate(next(begin(base)), end(base), *begin(base), + [](StrRange bounds, const StrRange& rng) noexcept { + bounds.start = std::min(rng.start, bounds.start); + bounds.finish = std::max(rng.finish, bounds.finish); + return bounds; + }); + } + } +}; + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26446 ) // Note: do not warn about indexes +#endif + +//! Evaluate codepoint size from first byte of UTF8 string +/* + Requires UTF8 conforming input +*/ +[[nodiscard]] constexpr int8_t UTF8CharSize(unsigned const char firstByte) noexcept { + constexpr unsigned char kFirstBitMask = 128; // 1000000 + constexpr unsigned char kThirdBitMask = 32; // 0010000 + constexpr unsigned char kFourthBitMask = 16; // 0001000 + if ((firstByte & kFirstBitMask) == 0) { + return 1; + } else if ((firstByte & kThirdBitMask) == 0) { + return 2; + } else if ((firstByte & kFourthBitMask) == 0) { + return 3; + } else { + return 4; + } +} + +//! iterator for UTF8 string +/* + Warning: iterator returns first byte of each codepoint. + To access UTF8 symbol one should use BytePosition and SymbolSize functions +*/ +class UTF8Iterator { +public: + // stl compatibility + using iterator_category = std::forward_iterator_tag; + using value_type = char; + using difference_type = std::ptrdiff_t; + using pointer = const char*; + using reference = const char&; + +public: + constexpr explicit UTF8Iterator(const std::string_view data, const StrPos position = 0) noexcept + : data{ data } { + if (position != endPos) { + GotoCodepoint(position); + } + } + + static constexpr StrPos endPos = -1; + +private: + StrPos current{ endPos }; + size_t bytePosition{ 0 }; + std::string_view data; + +public: + // Note: comparing iterators from different strings is unspecified behavior! + [[nodiscard]] bool operator==(const UTF8Iterator& rhs) const noexcept { + return current == rhs.current; + } + [[nodiscard]] bool operator!=(const UTF8Iterator& rhs) const noexcept { + return !(*this == rhs); + } + + UTF8Iterator& operator++() noexcept { + bytePosition += SymbolSize(); // Note: range check not needed + ++current; + if (size(data) <= bytePosition) { + current = endPos; + } + return *this; + } + + [[nodiscard]] reference operator*() const noexcept { return data[bytePosition]; } + [[nodiscard]] size_t BytePosition() const noexcept { return bytePosition; } + [[nodiscard]] StrPos Position() const noexcept { return current; } + [[nodiscard]] size_t SymbolSize() const noexcept { + return static_cast(UTF8CharSize(static_cast(data[bytePosition]))); + } + +private: + void GotoCodepoint(const StrPos cpPosition) noexcept { + assert(cpPosition >= 0); + for (current = 0; current != cpPosition && size(data) > bytePosition; ++current) { + bytePosition += SymbolSize(); // Note: range check not needed + } + if (size(data) <= bytePosition) { + current = endPos; + } + }; +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +[[nodiscard]] constexpr UTF8Iterator UTF8Begin(const std::string_view source) { + return UTF8Iterator{ source }; +} + +[[nodiscard]] constexpr UTF8Iterator UTF8End(const std::string_view source) { + return UTF8Iterator{ source, UTF8Iterator::endPos }; +} + +[[nodiscard]] inline std::string_view Substr(const std::string_view source, const StrRange range) noexcept { + // Note: add constexpr in C++20 + const auto start = UTF8Iterator(source, range.start); + auto finish = UTF8Iterator(source, range.finish - 1); + if (start == UTF8End(source) || finish == UTF8End(source)) { + return {}; + } else if (++finish == UTF8End(source)) { + return source.substr(start.BytePosition(), size(source) - start.BytePosition()); + } else { + return source.substr(start.BytePosition(), finish.BytePosition() - start.BytePosition()); + } +} + +[[nodiscard]] inline StrPos SizeInCodePoints(const std::string_view utf8string) noexcept { + auto size = 0; + for (auto it = UTF8Begin(utf8string); it != UTF8End(utf8string); ++it, ++size) {} + return size; +} + +} // namespace ccl \ No newline at end of file diff --git a/ccl/cclCommons/include/ccl/Substitutes.hpp b/ccl/cclCommons/include/ccl/Substitutes.hpp new file mode 100644 index 0000000..9d2ed6d --- /dev/null +++ b/ccl/cclCommons/include/ccl/Substitutes.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +namespace ccl { + +using StrSubstitutes = std::unordered_map; +using StrTranslator = std::function(const std::string&)>; + +inline StrTranslator CreateTranslator(const StrSubstitutes& substitutes) { + return [&substitutes](const std::string& oldVal) -> StrTranslator::result_type { + if (!substitutes.contains(oldVal)) { + return std::nullopt; + } else { + return substitutes.at(oldVal); + } + }; +} + +inline StrTranslator CreateTranslator(StrSubstitutes&& substitutes) { + return [substitutes = std::move(substitutes)](const std::string& oldVal) -> StrTranslator::result_type { + if (!substitutes.contains(oldVal)) { + return std::nullopt; + } else { + return substitutes.at(oldVal); + } + }; +} + +} // namespace ccl \ No newline at end of file diff --git a/ccl/cclCommons/include/ccl/cclChange.hpp b/ccl/cclCommons/include/ccl/cclChange.hpp new file mode 100644 index 0000000..ac25c3d --- /dev/null +++ b/ccl/cclCommons/include/ccl/cclChange.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "ccl/cclTypes.hpp" + +#include +#include +#include +#include +#include + +namespace ccl::change { +using Hash = uint32_t; + +inline Hash HashString(const std::string& string) { + static constexpr auto BERNSTEIN_CONSTANT = 33U; + return std::accumulate(begin(string), end(string), Hash{ 0 }, + [&](Hash hash, char symbol) noexcept + { return hash * BERNSTEIN_CONSTANT + static_cast(symbol); }); +} + +//! Usage types enumeration +enum class Usage : uint8_t { + notUsed = 0, // не используется + asElement = 1, // Наследуется + asOption = 2, // Используется в таблице отождествлений +}; + +//! Abstract modification info +struct Modification {}; + +//! Abstract modification message +class ModMessage : public types::Message { + const Modification* modInfo{ nullptr }; + +public: + ModMessage() = default; + explicit ModMessage(const Modification& modInfo) noexcept + : modInfo{ &modInfo } {} + + [[nodiscard]] const Modification* GetModInfo() const noexcept { return modInfo; } + [[nodiscard]] uint32_t Type() const noexcept override { return modificationCode; } +}; + +//! Observable modifications base +class ObservableMods : public types::Observable { +protected: + void NotifyModification(const Modification& mod = {}) { + Notify(ModMessage{ mod }); + } +}; + +} // namespace ccl::change diff --git a/ccl/cclCommons/include/ccl/cclMeta.hpp b/ccl/cclCommons/include/ccl/cclMeta.hpp new file mode 100644 index 0000000..4218beb --- /dev/null +++ b/ccl/cclCommons/include/ccl/cclMeta.hpp @@ -0,0 +1,371 @@ +#pragma once +// Metaprogramming tools + +#include +#include +#include +#include +#include +#include + +namespace ccl::meta { + +//! Basic identity class for template overloading/specializations +template +struct Identity { using type = T; }; + +//! Naive propagate_const implementation aimed at unique_ptr +template +class PropagateConst { + // TODO: C++20 constexpr ctors + T pointer{ nullptr }; + +public: + ~PropagateConst() noexcept = default; + PropagateConst() = default; + + PropagateConst(const PropagateConst&) = delete; + PropagateConst& operator=(const PropagateConst&) = delete; + PropagateConst(PropagateConst&&) noexcept = default; + PropagateConst& operator=(PropagateConst&&) noexcept = default; + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + PropagateConst(T&& val) noexcept + : pointer{ std::move(val) } {} + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + PropagateConst(std::nullptr_t) noexcept {} + + template>> + PropagateConst(Up&& up) // NOLINT(google-explicit-constructor, hicpp-explicit-conversions, bugprone-forwarding-reference-overload) + : pointer{ std::forward(up) } {} + + template>> + PropagateConst(PropagateConst&& up) // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) + : pointer{ std::move(up.pointer) } {} + + template>> + constexpr PropagateConst& operator=(Up&& up) { + pointer = std::forward(up); + return *this; + } + + template>> + constexpr PropagateConst& operator=(PropagateConst&& up) { + pointer = std::move(up.pointer); + return *this; + } + +public: + using ElementType = std::remove_reference_t())>; + constexpr ElementType* get() { + return pointer.get(); + } + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + constexpr operator ElementType*() { + return get(); + } + constexpr ElementType& operator*() { + return *get(); + } + constexpr ElementType* operator->() { + return get(); + } + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + constexpr operator const ElementType*() const { + return get(); + } + [[nodiscard]] constexpr const ElementType* get() const { + return pointer.get(); + } + constexpr const ElementType& operator*() const { + return *get(); + } + constexpr const ElementType* operator->() const { + return get(); + } + + constexpr void swap(PropagateConst& second) noexcept { + std::swap(pointer, second.pointer); + } + + constexpr bool operator==(const PropagateConst& rhs) const noexcept { + return pointer == rhs.pointer; + } + constexpr bool operator!=(const PropagateConst& rhs) const noexcept { + return pointer != rhs.pointer; + } + constexpr bool operator==(std::nullptr_t) const noexcept { + return pointer == nullptr; + } + constexpr bool operator!=(std::nullptr_t) const noexcept { + return pointer != nullptr; + } +}; + +//! Unique pointer propagating const wrapper alias +template +using UniqueCPPtr = PropagateConst>; + +//! Grouping multiple overloaded lambas +/* + see https://www.youtube.com/watch?v=XjOVebhUOY around 20:30 +*/ +template +struct Overloads : Ops... { + using Ops::operator()...; +}; +template +Overloads(Ops...)->Overloads; + +//! Apply function object to tuples created from elements container +template + void ForEachPair(const Container& input, const Function& Fn) { + std::for_each(begin(input), end(input), [&input, &Fn](const Value& el1) { + std::for_each(begin(input), end(input), [&el1, &Fn](const Value& el2) { + Fn(el1, el2); + }); + }); +} + +//! CRTP implementation +template class crtpType> +struct crtp { + [[nodiscard]] Base& BaseT() noexcept { return static_cast(*this); } + [[nodiscard]] const Base& BaseT() const noexcept { return static_cast(*this); } +}; + +//! Abstract strong type +/* + see https://github.com/joboccara/NamedType +*/ +template +struct Incrementable : crtp { + T& operator+=(const T& other) { this->BaseT().get() += other.get(); return this->BaseT(); } +}; + +template +struct PreIncrementable : crtp { + T& operator++() { ++this->BaseT().get(); return this->BaseT(); } +}; + +template +struct Addable : crtp { + T operator+(const T& other) const { return T(this->BaseT().get() + other.get()); } +}; + +template +struct Subtractable : crtp { + T operator-(const T& other) const { return T(this->BaseT().get() - other.get()); } +}; + +template +struct Multiplicable : crtp { + T operator*(const T& other) const { return T(this->BaseT().get() * other.get()); } +}; + +template +struct Comparable : crtp { + bool operator==(const T& other) const noexcept { return this == &other || other.get() == this->BaseT().get(); } + bool operator!=(const T& other) const noexcept { return !(*this == other); } +}; + +template +struct Orderable : crtp { + bool operator<(const T& other) const noexcept { return this->BaseT().get() < other.get(); } + bool operator>(const T& other) const noexcept { return other.get() < this->BaseT().get(); } + bool operator<=(const T& other) const noexcept { return !(other.get() < this->BaseT().get()); } + bool operator>=(const T& other) const noexcept { return !(*this < other); } + bool operator==(const T& other) const noexcept { return !(*this < other) && !(other.get() < this->BaseT().get()); } + bool operator!=(const T& other) const noexcept { return !(*this == other); } +}; + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26482 26446) // Note: ignore bounds warning when trying to address massive of static values +#endif + +//! Iterable enumeration +template +class EnumIter { + size_t pos{ 0 }; + + static constexpr T values[] = { args... }; // NOLINT: static C array + static constexpr size_t enumSize = sizeof...(args); + +public: + EnumIter() = default; + explicit EnumIter(T val) + : pos(static_cast(std::distance(&values[0], find(&values[0], &values[enumSize], val)))) {} + +public: + // stl compatibility + using iterator_category = std::input_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + EnumIter end() noexcept { EnumIter result{}; result.pos = enumSize; return result; } + EnumIter begin() noexcept { return EnumIter{}; } + static constexpr size_t size() { return enumSize; } + + const T& operator*() const noexcept { return values[pos]; } + EnumIter& operator--() noexcept { --pos; return *this; } + EnumIter& operator++() noexcept { ++pos; return *this; } + + bool operator==(const EnumIter& rhs) const noexcept { return pos == rhs.pos; } + bool operator!=(const EnumIter& rhs) const noexcept { return pos != rhs.pos; } +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +//! Abstract mutating facet +/* + Note: facets are not movable and not copyable because of Core&. + Can use std::reference_wrapper instead if needed +*/ +template +struct MutatorFacet { + Core& core; + +protected: + ~MutatorFacet() noexcept = default; + +public: + MutatorFacet(const MutatorFacet&) = delete; + MutatorFacet& operator=(const MutatorFacet&) = delete; + + explicit MutatorFacet(Core& core) noexcept + : core{ core } {} +}; + +//! Abstract constant facet +template +struct ConstFacet { + const Core& core; + +protected: + ~ConstFacet() noexcept = default; + +public: + ConstFacet(const ConstFacet&) = delete; + ConstFacet& operator=(const ConstFacet&) = delete; + + explicit ConstFacet(const Core& core) noexcept : + core{ core } {} +}; + +//! Abstract polymorphic iterator +template +class PolyFCIterator { + struct ImplConcept; + template struct ImplModel; + + std::unique_ptr impl{ nullptr }; + +public: + ~PolyFCIterator() noexcept = default; + PolyFCIterator(const PolyFCIterator& rhs) + : impl{ rhs.impl->Clone() } {} + PolyFCIterator& operator=(const PolyFCIterator& rhs) { + if (this == &rhs) { + return *this; + } + impl = rhs.impl->Clone(); + return *this; + } + PolyFCIterator(PolyFCIterator&&) noexcept = default; + PolyFCIterator& operator=(PolyFCIterator&&) noexcept = default; + + template + explicit PolyFCIterator(const Iter& iter) + : impl{ std::make_unique>(iter) } {} + +public: + // stl compatibility + using iterator_category = std::forward_iterator_tag; + using value_type = Value; + using difference_type = std::ptrdiff_t; + using pointer = const Value*; + using reference = const Value&; + +private: + struct ImplConcept { + virtual ~ImplConcept() noexcept = default; + ImplConcept() = default; + ImplConcept(const ImplConcept&) = default; + ImplConcept& operator=(const ImplConcept&) = default; + ImplConcept(ImplConcept&&) noexcept = default; + ImplConcept& operator=(ImplConcept&&) noexcept = default; + + virtual void Next() = 0; + [[nodiscard]] virtual const value_type& Deref() const = 0; + [[nodiscard]] virtual bool Equal(const void* other) const = 0; + [[nodiscard]] virtual std::unique_ptr Clone() const = 0; + [[nodiscard]] virtual const std::type_info& Type() const noexcept = 0; + [[nodiscard]] virtual const void* Address() const noexcept = 0; + }; + + template + struct ImplModel : public ImplConcept { + Iter iter; + + explicit ImplModel(Iter iter) noexcept + : iter{ std::move(iter) } {} + + void Next() override { + std::advance(iter, 1); + } + [[nodiscard]] reference Deref() const override { + return *iter; + } + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: false positive noexcept +#endif + [[nodiscard]] bool Equal(const void* rp) const override { + return iter == static_cast(rp)->iter; + } +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + + [[nodiscard]] std::unique_ptr Clone() const override { + return std::make_unique(*this); + } + [[nodiscard]] const std::type_info& Type() const noexcept override { + return typeid(iter); + } + [[nodiscard]] const void* Address() const noexcept override { + return this; + } + }; + +public: + reference operator*() const { return impl->Deref(); } + pointer operator->() const { return &impl->Deref(); } + PolyFCIterator& operator++() { + impl->Next(); + return *this; + } + bool operator==(const PolyFCIterator& rhs) const { + return impl->Type() == rhs.impl->Type() && impl->Equal(rhs.impl->Address()); + } + bool operator!=(const PolyFCIterator& r) const { + return !(*this == r); + } +}; + +} // namespace ccl::meta diff --git a/ccl/cclCommons/include/ccl/cclTypes.hpp b/ccl/cclCommons/include/ccl/cclTypes.hpp new file mode 100644 index 0000000..7afa9a0 --- /dev/null +++ b/ccl/cclCommons/include/ccl/cclTypes.hpp @@ -0,0 +1,239 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ccl { + +//! Comparison result for non-linear order +enum class Comparison : uint8_t { + LESS, + EQUAL, + GREATER, + INCOMPARABLE +}; + +//! Static fixed size BiMap with linear search access. Use preferably in constexpr context and only for small sizes +template +struct StaticMap { + using DataType = std::array, Size>; + DataType data; + + [[nodiscard]] constexpr bool ContainsKey(const Key& key) const noexcept { + const auto itr = + std::find_if(begin(data), end(data), + [&key](const auto& v) { return v.first == key; }); + if (itr != end(data)) { + return true; + } else { + return false; + } + } + + [[nodiscard]] constexpr bool ContainsValue(const Value& value) const noexcept { + const auto itr = + std::find_if(begin(data), end(data), + [&value](const auto& v) { return v.second == value; }); + if (itr != end(data)) { + return true; + } else { + return false; + } + } + + [[nodiscard]] constexpr Value AtKey(const Key& key) const { + const auto itr = + std::find_if(begin(data), end(data), + [&key](const auto& v) { return v.first == key; }); + if (itr != end(data)) { + return itr->second; + } else { + throw std::range_error("Not Found"); + } + } + + [[nodiscard]] constexpr Key AtValue(const Value& value) const { + const auto itr = + std::find_if(begin(data), end(data), + [&value](const auto& v) { return v.second == value; }); + if (itr != end(data)) { + return itr->first; + } else { + throw std::range_error("Not Found"); + } + } +}; + +} // namespace ccl + +namespace ccl::types { +//! Automatic counter guard +template +class CounterGuard { + T* counter; + +public: + ~CounterGuard() noexcept { + if (counter != nullptr) { + --(*counter); + } + } + constexpr explicit CounterGuard(T& counterRef) noexcept + : counter(&counterRef) { + ++(*counter); + } + CounterGuard(const CounterGuard&) = delete; + CounterGuard& operator=(const CounterGuard&) = delete; + CounterGuard(CounterGuard&&) noexcept = default; + CounterGuard& operator=(CounterGuard&&) noexcept = default; + + void Release() { + if (counter != nullptr) { + --(*counter); + counter = nullptr; + } + } +}; + +// Note: possibly not thread-safe. If needed thread-safe - make counter atomic +class GuardableBool { + bool value; + uint16_t guardCounter{ 0 }; + +public: + constexpr explicit GuardableBool(const bool value) + : value{ value } {} + constexpr GuardableBool(const GuardableBool& rhs) + : value{ rhs.value } {} + GuardableBool& operator=(const GuardableBool& rhs) noexcept { + if (&rhs != this) { + value = rhs.value; + } + return *this; + } + GuardableBool(GuardableBool&&) noexcept = default; + GuardableBool& operator=(GuardableBool&&) noexcept = default; + +public: + using Guard = CounterGuard; + + explicit(false) constexpr operator bool() const noexcept { return IsGuarded() != value; } + + [[nodiscard]] constexpr bool IsGuarded() const noexcept { return guardCounter > 0; } + [[nodiscard]] Guard CreateGuard() noexcept { return Guard{ guardCounter }; } +}; + +//! Abstract message for observer +class Message { +public: + virtual ~Message() noexcept = default; + +protected: + Message() = default; + Message(const Message&) = default; + Message& operator=(const Message&) = default; + Message(Message&&) noexcept = default; + Message& operator=(Message&&) noexcept = default; + +public: + static constexpr auto modificationCode = 0x1000U; + static constexpr auto srcCode = 0x2000U; + + [[nodiscard]] virtual uint32_t Type() const noexcept = 0; +}; + +//! Message with no payload +struct BasicMsg final : Message { + uint32_t msgID; + + explicit BasicMsg(uint32_t msgID) noexcept + : msgID{ msgID } {} + [[nodiscard]] uint32_t Type() const noexcept override { + return msgID; + } +}; + +//! Observer base class +class Observable; +class Observer { + friend class Observable; + + types::GuardableBool isObserving{ true }; + +public: + virtual ~Observer() noexcept = default; + +protected: + Observer() = default; + Observer(const Observer&) = default; + Observer& operator=(const Observer&) = default; + Observer(Observer&&) noexcept = default; + Observer& operator=(Observer&&) noexcept = default; + +protected: + [[nodiscard]] bool DndStatus() const noexcept { + return !isObserving; + } + [[nodiscard]] auto DndGuard() noexcept { + return isObserving.CreateGuard(); + } + virtual void OnObserve(const Message& msg) = 0; + +private: + void TryInvoking(const Message& msg) { + if (isObserving) { + OnObserve(msg); + } + } +}; + +//! Observable base class +class Observable { + std::vector observers{}; + +public: + void AddObserver(Observer& obs) { + observers.emplace_back(&obs); + } + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26447 ) // Do not warn about using noexcept +#endif + + void RemoveObserver(const Observer& obs) noexcept { + if (!empty(observers)) { // Note: After this check shouldnt throw (unless used in threaded environement) + observers.erase(std::remove(begin(observers), end(observers), &obs), end(observers)); + } + } + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + + void ImportObserversFrom(Observable& rhs) { + if (this != &rhs) { + for (auto& obs : rhs.observers) { + AddObserver(*obs); + } + } + } + +protected: + // Note: notifying dangling observer is UB! Observer should use move semantic + void Notify(uint32_t msgID) { + Notify(BasicMsg{ msgID }); + } + void Notify(const Message& msg) { + for (auto& oberver : observers) { + oberver->TryInvoking(msg); + } + } +}; + +} // namespace ccl::types \ No newline at end of file diff --git a/ccl/cclCommons/test/CMakeLists.txt b/ccl/cclCommons/test/CMakeLists.txt new file mode 100644 index 0000000..9358b35 --- /dev/null +++ b/ccl/cclCommons/test/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.23) + +find_package(GTest REQUIRED) + +add_executable(cclCommons_Tests) +target_sources(cclCommons_Tests + PRIVATE + unity/cclCommonsTest.cpp +) +target_include_directories(cclCommons_Tests + PRIVATE + ../include + utils +) +target_link_libraries(cclCommons_Tests + PRIVATE + ccl_CXXwarnings + ccl_CXXoptions + GTest::gtest + GTest::gtest_main +) + +include(GoogleTest) +gtest_discover_tests(cclCommons_Tests) \ No newline at end of file diff --git a/ccl/cclCommons/test/cclCommonsTest.vcxproj b/ccl/cclCommons/test/cclCommonsTest.vcxproj new file mode 100644 index 0000000..84ea660 --- /dev/null +++ b/ccl/cclCommons/test/cclCommonsTest.vcxproj @@ -0,0 +1,211 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {53A380CF-B599-4170-89B1-642F1C3772E1} + Win32Proj + 10.0 + Application + v143 + Unicode + cclCommonsTest + + + + true + + + + true + + + + true + + + true + + + + + + + + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + + + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + false + + + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + false + + + + + + + + + + + + + + + + + + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;%(AdditionalIncludeDirectories) + Disabled + true + true + + + true + Console + false + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;%(AdditionalIncludeDirectories) + Disabled + false + true + true + + + true + Console + false + + + + + NotUsing + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + UseLinkTimeCodeGeneration + + + true + + + + + NotUsing + + + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + UseLinkTimeCodeGeneration + + + true + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/ccl/cclCommons/test/cclCommonsTest.vcxproj.filters b/ccl/cclCommons/test/cclCommonsTest.vcxproj.filters new file mode 100644 index 0000000..1b35189 --- /dev/null +++ b/ccl/cclCommons/test/cclCommonsTest.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {ed04b33d-515f-46b0-aad1-54dcbc55a5fd} + + + {4c4173ff-1f15-4919-90b9-3d43cc164f84} + + + {be31e9f2-602c-4c10-b9ed-7407342449f4} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + + + utils + + + include + + + include + + + include + + + include + + + include + + + \ No newline at end of file diff --git a/ccl/cclCommons/test/packages.config b/ccl/cclCommons/test/packages.config new file mode 100644 index 0000000..be1fa03 --- /dev/null +++ b/ccl/cclCommons/test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testGuard.cpp b/ccl/cclCommons/test/src/testGuard.cpp new file mode 100644 index 0000000..e89e323 --- /dev/null +++ b/ccl/cclCommons/test/src/testGuard.cpp @@ -0,0 +1,69 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/cclTypes.hpp" + +namespace ct = ccl::types; + +TEST(UTGuard, CounterIncrement) { + auto c = 0; + const auto guard = ct::CounterGuard(c); + EXPECT_EQ(c, 1); +} + +TEST(UTGuard, CounterDecrementOnDestroy) { + auto c = 0; + { + const auto guard = ct::CounterGuard(c); + EXPECT_EQ(c, 1); + } + EXPECT_EQ(c, 0); +} + +TEST(UTGuard, CounterDoubleGuard) { + auto c = 0; + { + const auto guard1 = ct::CounterGuard(c); + EXPECT_EQ(c, 1); + { + const auto guard2 = ct::CounterGuard(c); + EXPECT_EQ(c, 2); + } + EXPECT_EQ(c, 1); + } + EXPECT_EQ(c, 0); +} + +TEST(UTGuard, CounterRelease) { + auto c = 0; + { + auto guard = ct::CounterGuard(c); + EXPECT_EQ(c, 1); + guard.Release(); + EXPECT_EQ(c, 0); + } + EXPECT_EQ(c, 0); +} + +TEST(UTGuard, GuardableDefault) { + const auto val = ct::GuardableBool{ true }; + EXPECT_TRUE(val); + EXPECT_FALSE(val.IsGuarded()); + + const auto val2 = ct::GuardableBool{ false }; + EXPECT_FALSE(val2); + EXPECT_FALSE(val2.IsGuarded()); +} + +TEST(UTGuard, GuardableSpawnGuard) { + auto val = ct::GuardableBool{ true }; + const auto guard = val.CreateGuard(); + EXPECT_FALSE(val); + EXPECT_TRUE(val.IsGuarded()); + + auto val2 = ct::GuardableBool{ false }; + const auto guard2 = val2.CreateGuard(); + EXPECT_TRUE(val2); + EXPECT_TRUE(val2.IsGuarded()); +} \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testObserver.cpp b/ccl/cclCommons/test/src/testObserver.cpp new file mode 100644 index 0000000..04fd6f1 --- /dev/null +++ b/ccl/cclCommons/test/src/testObserver.cpp @@ -0,0 +1,83 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "FakeObserver.hpp" + +namespace ct = ccl::types; + +class UTObserver : public ::testing::Test { +public: + FakeObserver obs{}; + FakeObservable object{}; +}; + +TEST_F(UTObserver, BasicMod) { + auto basic = ct::BasicMsg{ 42U }; + EXPECT_EQ(basic.Type(), 42U); +} + +TEST_F(UTObserver, NoObservers) { + EXPECT_NO_THROW(object.Notify(42U)); + EXPECT_NO_THROW(object.Notify(ct::BasicMsg{ 42U })); +} + +TEST_F(UTObserver, AddObserver) { + object.AddObserver(obs); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 1); +} + +TEST_F(UTObserver, ImportObservers) { + object.AddObserver(obs); + FakeObservable anotherObj{}; + anotherObj.ImportObserversFrom(object); + + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 1); + + anotherObj.Notify(42U); + EXPECT_EQ(ssize(obs.events), 2); +} + +TEST_F(UTObserver, AddDoubleObserver) { + object.AddObserver(obs); + object.AddObserver(obs); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 2); +} + +TEST_F(UTObserver, RemoveObserver) { + object.AddObserver(obs); + object.RemoveObserver(obs); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 0); +} + +TEST_F(UTObserver, RemoveDoubleObserver) { + object.AddObserver(obs); + object.AddObserver(obs); + object.RemoveObserver(obs); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 0); +} + +TEST_F(UTObserver, Notify) { + object.AddObserver(obs); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 1); + EXPECT_EQ(obs.events[0], 42U); +} + +TEST_F(UTObserver, DndStatus) { + EXPECT_FALSE(obs.DndStatus()); + auto guard = obs.DndGuard(); + EXPECT_TRUE(obs.DndStatus()); +} + +TEST_F(UTObserver, DndBlockObserve) { + object.AddObserver(obs); + auto guard = obs.DndGuard(); + object.Notify(42U); + EXPECT_EQ(ssize(obs.events), 0); +} \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testPropagateConst.cpp b/ccl/cclCommons/test/src/testPropagateConst.cpp new file mode 100644 index 0000000..ee500ce --- /dev/null +++ b/ccl/cclCommons/test/src/testPropagateConst.cpp @@ -0,0 +1,126 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/cclMeta.hpp" + +// helper classes +struct Base { + int32_t state{ 1337 }; + + virtual ~Base() = default; + + virtual int32_t overloadedFunc() const { + return 42; + } + virtual int32_t overloadedFunc() { + return 43; + } +}; + +struct Derived1 : Base { + int32_t additionalState{ 42 }; + + int32_t overloadedFunc() const override { + return 1337; + } +}; + +struct Derived2 : Base { + std::string additionalState{ "str42" }; + + int32_t overloadedFunc() override { + return 1337; + } +}; + +TEST(UTPropagateConst, AccessValue) { + using ccl::meta::UniqueCPPtr; + UniqueCPPtr intCP{ std::make_unique(42) }; + const auto& constRef = intCP; + + EXPECT_EQ(intCP.operator*(), 42); + EXPECT_EQ(constRef.operator*(), 42); + + EXPECT_EQ(intCP.get(), constRef.get()); + EXPECT_EQ(intCP.operator->(), constRef.get()); + EXPECT_EQ(static_cast(intCP), constRef.get()); + EXPECT_EQ(static_cast(constRef), constRef.get()); +} + +TEST(UTPropagateConst, Nullptr) { + using ccl::meta::UniqueCPPtr; + const UniqueCPPtr intPtr{}; + EXPECT_TRUE(intPtr == nullptr); + EXPECT_FALSE(intPtr != nullptr); + EXPECT_EQ(intPtr, UniqueCPPtr(nullptr)); + + UniqueCPPtr notNull{ std::make_unique(42) }; + EXPECT_FALSE(notNull == nullptr); + EXPECT_TRUE(notNull != nullptr); + + notNull = nullptr; + EXPECT_TRUE(notNull == nullptr); + + notNull = std::make_unique(0); + EXPECT_FALSE(notNull == nullptr); +} + +TEST(UTPropagateConst, PointerEquality) { + using ccl::meta::UniqueCPPtr; + UniqueCPPtr int1{ std::make_unique(42) }; + UniqueCPPtr int2{ std::make_unique(42) }; + UniqueCPPtr int3{ std::make_unique(1337) }; + const auto& constRef1 = int1; + const auto& constRef2 = int2; + const auto& constRef3 = int3; + + EXPECT_EQ(int1, constRef1); + EXPECT_NE(int1, int2); + EXPECT_NE(int1, int3); + EXPECT_NE(constRef1, int3); + EXPECT_NE(constRef1, constRef3); + EXPECT_NE(int1, constRef2); + EXPECT_NE(constRef1, constRef2); + +} + +TEST(UTPropagateConst, Swap) { + using ccl::meta::UniqueCPPtr; + UniqueCPPtr int1{ std::make_unique(42) }; + std::swap(int1, int1); + EXPECT_EQ(*int1, 42); + + UniqueCPPtr int2{ std::make_unique(1337) }; + std::swap(int1, int2); + EXPECT_EQ(*int2, 42); + EXPECT_EQ(*int1, 1337); +} + +TEST(UTPropagateConst, Propagation) { + using ccl::meta::UniqueCPPtr; + UniqueCPPtr nonConstPtr{ std::make_unique() }; + const auto& constRef = nonConstPtr; + EXPECT_EQ(nonConstPtr->overloadedFunc(), 43); + EXPECT_EQ(constRef->overloadedFunc(), 42); +} + +TEST(UTPropagateConst, Polymorphism) { + using ccl::meta::UniqueCPPtr; + UniqueCPPtr basePtrToDerived1{}, basePtrToDerived2{}; + basePtrToDerived1 = UniqueCPPtr{ std::make_unique() }; + basePtrToDerived2 = UniqueCPPtr{ std::make_unique() }; + + ASSERT_FALSE(dynamic_cast(basePtrToDerived1.get()) == nullptr); + EXPECT_TRUE(dynamic_cast(basePtrToDerived1.get()) == nullptr); + EXPECT_EQ(dynamic_cast(basePtrToDerived1.get())->additionalState, 42); + EXPECT_EQ(dynamic_cast(basePtrToDerived2.get())->additionalState, "str42"); + + const auto& constRef1 = basePtrToDerived1; + EXPECT_EQ(basePtrToDerived1->overloadedFunc(), 43); + EXPECT_EQ(constRef1->overloadedFunc(), 1337); + + const auto& constRef2 = basePtrToDerived2; + EXPECT_EQ(basePtrToDerived2->overloadedFunc(), 1337); + EXPECT_EQ(constRef2->overloadedFunc(), 42); +} \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testStaticMap.cpp b/ccl/cclCommons/test/src/testStaticMap.cpp new file mode 100644 index 0000000..73261e2 --- /dev/null +++ b/ccl/cclCommons/test/src/testStaticMap.cpp @@ -0,0 +1,49 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/cclTypes.hpp" + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 4834 6031 ) +#endif + +class UTStaticMap : public ::testing::Test { +protected: + using MapType = ccl::StaticMap; + using ValueType = MapType::DataType::value_type; + static constexpr MapType testMap{ + MapType::DataType({ ValueType{"A", 1}, ValueType{"B", 42}, ValueType{"C", 55}, ValueType{"Hello", 1337} }) + }; +}; + +TEST_F(UTStaticMap, ContainsKey) { + EXPECT_TRUE(testMap.ContainsKey("Hello")); + EXPECT_TRUE(testMap.ContainsKey("A")); + EXPECT_FALSE(testMap.ContainsKey("")); + EXPECT_FALSE(testMap.ContainsKey(" ")); + EXPECT_FALSE(testMap.ContainsKey("invalid")); +} + +TEST_F(UTStaticMap, ContainsValue) { + EXPECT_TRUE(testMap.ContainsValue(1)); + EXPECT_TRUE(testMap.ContainsValue(1337)); + EXPECT_FALSE(testMap.ContainsValue(-1)); + EXPECT_FALSE(testMap.ContainsValue(0)); + EXPECT_FALSE(testMap.ContainsValue(1338)); +} + +TEST_F(UTStaticMap, AtKey) { + EXPECT_EQ(testMap.AtKey("A"), 1); + EXPECT_EQ(testMap.AtKey("Hello"), 1337); +} + +TEST_F(UTStaticMap, AtValue) { + EXPECT_EQ(testMap.AtValue(1), "A"); + EXPECT_EQ(testMap.AtValue(1337), "Hello"); +} + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testStrings.cpp b/ccl/cclCommons/test/src/testStrings.cpp new file mode 100644 index 0000000..b187029 --- /dev/null +++ b/ccl/cclCommons/test/src/testStrings.cpp @@ -0,0 +1,384 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/Strings.hpp" + +using ccl::operator""_c17; + +class UTStrings : public ::testing::Test { +protected: + using StrRange = ccl::StrRange; + using UTF8Iterator = ccl::UTF8Iterator; +}; + +TEST_F(UTStrings, Length) { + EXPECT_TRUE(StrRange{}.length() == 0); + EXPECT_TRUE(StrRange(1, 1).length() == 0); + EXPECT_TRUE(StrRange(2, 4).length() == 2); + EXPECT_TRUE(StrRange(4, 2).length() == -2); +} + +TEST_F(UTStrings, Shift) { + EXPECT_EQ(StrRange(4, 6), StrRange(2, 4).Shift(2)); + EXPECT_EQ(StrRange(0, 2), StrRange(2, 4).Shift(-2)); +} + +TEST_F(UTStrings, Equals) { + EXPECT_EQ(StrRange(1, 1), StrRange(1, 1)); + EXPECT_NE(StrRange(1, 2), StrRange(1, 1)); + EXPECT_NE(StrRange(2, 1), StrRange(1, 1)); + EXPECT_EQ(StrRange(2, 1), StrRange(2, 1)); + EXPECT_EQ(StrRange(1, 2), StrRange(1, 2)); + EXPECT_NE(StrRange(2, 1), StrRange(1, 2)); +} + +TEST_F(UTStrings, Collapse) { + EXPECT_EQ(StrRange(4, 4), StrRange(2, 4).CollapseEnd()); + EXPECT_EQ(StrRange(2, 2), StrRange(2, 4).CollapseStart()); +} + +TEST_F(UTStrings, Contains) { + EXPECT_TRUE(StrRange(1, 3).Contains(1)); + EXPECT_TRUE(StrRange(1, 3).Contains(2)); + EXPECT_FALSE(StrRange(1, 3).Contains(3)); + EXPECT_FALSE(StrRange(1, 3).Contains(4)); + EXPECT_FALSE(StrRange(1, 3).Contains(0)); + + EXPECT_TRUE(StrRange(2, 5).Contains(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(1, 6))); + EXPECT_TRUE(StrRange(2, 5).Contains(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(2, 6))); + EXPECT_TRUE(StrRange(2, 5).Contains(StrRange(3, 4))); + EXPECT_TRUE(StrRange(2, 5).Contains(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).Contains(StrRange(6, 7))); +} + +TEST_F(UTStrings, SharesBorder) { + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(0, 1))); + EXPECT_TRUE(StrRange(2, 5).SharesBorder(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(3, 6))); + EXPECT_TRUE(StrRange(2, 5).SharesBorder(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).SharesBorder(StrRange(6, 7))); +} + +TEST_F(UTStrings, Overlaps) { + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).Overlaps(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).Overlaps(StrRange(1, 2))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(1, 3))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(1, 5))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(1, 6))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(2, 3))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(2, 6))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(3, 4))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(3, 5))); + EXPECT_TRUE(StrRange(2, 5).Overlaps(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).Overlaps(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).Overlaps(StrRange(6, 7))); +} + +TEST_F(UTStrings, IsBefore) { + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).IsBefore(StrRange(5, 6))); + EXPECT_TRUE(StrRange(2, 5).IsBefore(StrRange(6, 7))); +} + +TEST_F(UTStrings, IsAfter) { + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(2, 5))); + + EXPECT_TRUE(StrRange(2, 5).IsAfter(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).IsAfter(StrRange(6, 7))); +} + +TEST_F(UTStrings, Meets) { + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(3, 6))); + EXPECT_TRUE(StrRange(2, 5).Meets(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).Meets(StrRange(6, 7))); +} + +TEST_F(UTStrings, Starts) { + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(2, 3))); + EXPECT_TRUE(StrRange(2, 5).Starts(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).Starts(StrRange(6, 7))); +} + +TEST_F(UTStrings, Finishes) { + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(1, 3))); + EXPECT_TRUE(StrRange(2, 5).Finishes(StrRange(1, 5))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).Finishes(StrRange(6, 7))); +} + +TEST_F(UTStrings, IsDuring) { + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(2, 5))); + + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(0, 1))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(1, 2))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(1, 3))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(1, 5))); + EXPECT_TRUE(StrRange(2, 5).IsDuring(StrRange(1, 6))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(2, 3))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(2, 6))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(3, 4))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(3, 5))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(3, 6))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(5, 6))); + EXPECT_FALSE(StrRange(2, 5).IsDuring(StrRange(6, 7))); +} + +TEST_F(UTStrings, Merge) { + EXPECT_EQ(StrRange::Merge({}), StrRange{}); + EXPECT_EQ(StrRange::Merge({ StrRange(1, 2), StrRange(2, 4) }), StrRange(1, 4)); + EXPECT_EQ(StrRange::Merge({ StrRange(2, 4), StrRange(1, 2) }), StrRange(1, 4)); + EXPECT_EQ(StrRange::Merge({ StrRange(1, 2), StrRange(3, 4) }), StrRange(1, 4)); + EXPECT_EQ(StrRange::Merge({ StrRange(1, 3), StrRange(2, 4) }), StrRange(1, 4)); +} + +TEST_F(UTStrings, Substr) { + EXPECT_EQ(ccl::Substr("", StrRange{ 0, 0 }), ""); + EXPECT_EQ(ccl::Substr("012345", StrRange(0, 3)), "012"); + EXPECT_EQ(ccl::Substr("012345", StrRange(0, 10)), ""); + EXPECT_EQ(ccl::Substr("012345", StrRange(2, 3)), "2"); + EXPECT_EQ(ccl::Substr(u8"ab\u212Ccd"_c17, StrRange(2, 4)), u8"\u212Cc"_c17); +} + +TEST_F(UTStrings, CharSize) { + EXPECT_EQ(ccl::UTF8CharSize(static_cast(std::string("a").at(0U))), 1); + EXPECT_EQ(ccl::UTF8CharSize(static_cast(std::string("1").at(0U))), 1); + EXPECT_EQ(ccl::UTF8CharSize(static_cast(u8"\u0435"_c17.at(0U))), 2); + EXPECT_EQ(ccl::UTF8CharSize(static_cast(std::string("\xE2\x84\xAC").at(0U))), 3); + EXPECT_EQ(ccl::UTF8CharSize(static_cast(std::string("\xF0\xA0\x9C\x8E").at(0U))), 4); +} + +TEST_F(UTStrings, UTF8Iteration) { + EXPECT_EQ(ccl::UTF8End({}), UTF8Iterator({})); + + const auto text = u8"\u212Cabc\u212Ccba\u212C"_c17; + auto it = UTF8Iterator(text); + EXPECT_EQ(*it, '\xE2'); + EXPECT_EQ(it.BytePosition(), 0U); + EXPECT_EQ(it.Position(), 0); + EXPECT_EQ(it.SymbolSize(), 3U); + + EXPECT_EQ(*++it, 'a'); + EXPECT_EQ(it.BytePosition(), 3U); + EXPECT_EQ(it.Position(), 1); + EXPECT_EQ(it.SymbolSize(), 1U); + + EXPECT_EQ(*++it, 'b'); + EXPECT_EQ(it.BytePosition(), 4U); + EXPECT_EQ(it.Position(), 2); + + EXPECT_EQ(*++it, 'c'); + EXPECT_EQ(it.BytePosition(), 5U); + EXPECT_EQ(it.Position(), 3); + + EXPECT_EQ(*++it, '\xE2'); + EXPECT_EQ(it.BytePosition(), 6U); + EXPECT_EQ(it.Position(), 4); + + EXPECT_EQ(*++it, 'c'); + EXPECT_EQ(it.BytePosition(), 9U); + EXPECT_EQ(it.Position(), 5); + + EXPECT_EQ(*++it, 'b'); + EXPECT_EQ(it.BytePosition(), 10U); + EXPECT_EQ(it.Position(), 6); + + EXPECT_EQ(*++it, 'a'); + EXPECT_EQ(it.BytePosition(), 11U); + EXPECT_EQ(it.Position(), 7); + + EXPECT_EQ(*++it, '\xE2'); + EXPECT_EQ(it.BytePosition(), 12U); + EXPECT_EQ(it.Position(), 8); + + EXPECT_EQ(++it, ccl::UTF8End(text)); +} + +TEST_F(UTStrings, IteratorCreation) { + EXPECT_EQ(UTF8Iterator("123", 42), ccl::UTF8End("123")); + EXPECT_EQ(UTF8Iterator("123", -1), ccl::UTF8End("123")); + EXPECT_EQ(UTF8Iterator("\xE2\x84\xAC", 1), ccl::UTF8End("\xE2\x84\xAC")); +} + +TEST_F(UTStrings, SizeInCodePoints) { + EXPECT_EQ(ccl::SizeInCodePoints({}), 0); + EXPECT_EQ(ccl::SizeInCodePoints(""), 0); + EXPECT_EQ(ccl::SizeInCodePoints("42"), 2); + EXPECT_EQ(ccl::SizeInCodePoints(u8"\u212C42"_c17), 3); +} + +TEST_F(UTStrings, SplitBySymbol) { + using ccl::SplitBySymbol; + { + const std::string str = ""; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 1); + EXPECT_TRUE(tokens[0] == ""); + } + { + const std::string str = "A,B,C"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 3); + EXPECT_TRUE(tokens[0] == "A"); + EXPECT_TRUE(tokens[1] == "B"); + EXPECT_TRUE(tokens[2] == "C"); + } + { + const std::string str = ",B,C"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 3); + EXPECT_TRUE(tokens[0] == ""); + EXPECT_TRUE(tokens[1] == "B"); + EXPECT_TRUE(tokens[2] == "C"); + } + { + const std::string str = "A,B,"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 3); + EXPECT_TRUE(tokens[0] == "A"); + EXPECT_TRUE(tokens[1] == "B"); + EXPECT_TRUE(tokens[2] == ""); + } + { + const std::string str = "A"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 1); + EXPECT_TRUE(tokens[0] == "A"); + } + { + const std::string str = ","; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 2); + EXPECT_TRUE(tokens[0] == ""); + EXPECT_TRUE(tokens[1] == ""); + } + { + const std::string str = ",,"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 3); + EXPECT_TRUE(tokens[0] == ""); + EXPECT_TRUE(tokens[1] == ""); + EXPECT_TRUE(tokens[2] == ""); + } + { + const std::string str = "A,"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 2); + EXPECT_TRUE(tokens[0] == "A"); + EXPECT_TRUE(tokens[1] == ""); + } + { + const std::string str = ",B"; + auto tokens = SplitBySymbol(str, ','); + EXPECT_TRUE(tokens.size() == 2); + EXPECT_TRUE(tokens[0] == ""); + EXPECT_TRUE(tokens[1] == "B"); + } +} + +TEST_F(UTStrings, TrimWhitespace) { + using ccl::TrimWhitespace; + EXPECT_EQ(TrimWhitespace(""), ""); + EXPECT_EQ(TrimWhitespace(" "), ""); + EXPECT_EQ(TrimWhitespace(" "), ""); + EXPECT_EQ(TrimWhitespace(" 1 "), "1"); + EXPECT_EQ(TrimWhitespace(" 1 "), "1"); + EXPECT_EQ(TrimWhitespace(" 1"), "1"); + EXPECT_EQ(TrimWhitespace("1 "), "1"); + EXPECT_EQ(TrimWhitespace(" 1 2 3 "), "1 2 3"); + EXPECT_EQ(TrimWhitespace(" 1 2 3 "), "1 2 3"); + EXPECT_EQ(TrimWhitespace("1 2 3 "), "1 2 3"); + EXPECT_EQ(TrimWhitespace("1 2 3"), "1 2 3"); + EXPECT_EQ(TrimWhitespace(" , "), ","); +} + +TEST_F(UTStrings, IsInteger) { + using ccl::IsInteger; + EXPECT_FALSE(IsInteger("")); + EXPECT_FALSE(IsInteger(" ")); + EXPECT_FALSE(IsInteger("-")); + EXPECT_FALSE(IsInteger("1-2")); + EXPECT_FALSE(IsInteger("-1-2")); + EXPECT_FALSE(IsInteger("-1-")); + EXPECT_TRUE(IsInteger("0")); + EXPECT_TRUE(IsInteger("00")); + EXPECT_TRUE(IsInteger("1")); + EXPECT_TRUE(IsInteger("-1")); + EXPECT_TRUE(IsInteger("1234")); + EXPECT_TRUE(IsInteger("-1234")); + EXPECT_TRUE(IsInteger("-9876543210")); + EXPECT_TRUE(IsInteger("007")); +} \ No newline at end of file diff --git a/ccl/cclCommons/test/src/testSubstitutes.cpp b/ccl/cclCommons/test/src/testSubstitutes.cpp new file mode 100644 index 0000000..d4c9c40 --- /dev/null +++ b/ccl/cclCommons/test/src/testSubstitutes.cpp @@ -0,0 +1,22 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/Substitutes.hpp" + +TEST(UTSubstitutes, CreateTranslator) { + const ccl::StrSubstitutes subst{ {"X1", "X2"}, {"X2","X3"} }; + const auto translator = ccl::CreateTranslator(subst); + ASSERT_TRUE(translator("X1").has_value()); + ASSERT_FALSE(translator("X3").has_value()); + EXPECT_EQ(translator("X1").value(), "X2"); + EXPECT_EQ(translator("X2").value(), "X3"); +} + +TEST(UTSubstitutes, CreateMoveTranslator) { + const auto translator = ccl::CreateTranslator({ {"X1", "X2"}, {"X2","X3"} }); + ASSERT_TRUE(translator("X1").has_value()); + ASSERT_FALSE(translator("X3").has_value()); + EXPECT_EQ(translator("X1").value(), "X2"); + EXPECT_EQ(translator("X2").value(), "X3"); +} \ No newline at end of file diff --git a/ccl/cclCommons/test/unity/cclCommonsTest.cpp b/ccl/cclCommons/test/unity/cclCommonsTest.cpp new file mode 100644 index 0000000..4dbf683 --- /dev/null +++ b/ccl/cclCommons/test/unity/cclCommonsTest.cpp @@ -0,0 +1,12 @@ +//! Unity build for cclCommons tests + +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "../src/testGuard.cpp" +#include "../src/testObserver.cpp" +#include "../src/testPropagateConst.cpp" +#include "../src/testStaticMap.cpp" +#include "../src/testStrings.cpp" +#include "../src/testSubstitutes.cpp" \ No newline at end of file diff --git a/ccl/cclCommons/test/utils/FakeObserver.hpp b/ccl/cclCommons/test/utils/FakeObserver.hpp new file mode 100644 index 0000000..007bf95 --- /dev/null +++ b/ccl/cclCommons/test/utils/FakeObserver.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "ccl/cclTypes.hpp" + +#include +#include +#include + +struct FakeObserver : ccl::types::Observer { + std::vector events{}; + + void OnObserve(const ccl::types::Message& msg) override { + events.emplace_back(msg.Type()); + } + + auto DndGuard() { return ccl::types::Observer::DndGuard(); } + [[nodiscard]] bool DndStatus() const noexcept { return Observer::DndStatus(); } +}; + +struct FakeObservable : ccl::types::Observable { + void Notify(const uint32_t msgID) { ccl::types::Observable::Notify(msgID); } + void Notify(const ccl::types::Message& msg) { ccl::types::Observable::Notify(msg); } +}; \ No newline at end of file diff --git a/ccl/cclGraph/CMakeLists.txt b/ccl/cclGraph/CMakeLists.txt new file mode 100644 index 0000000..651b642 --- /dev/null +++ b/ccl/cclGraph/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 3.23) + +project (cclGraph VERSION 1.2.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +## +## Project options +## +option(CC_BuildTests "Include tests executable" TRUE) +option(CC_UseSanitizers "Use sanitizers" FALSE) + +## Compiler options +include(../cmake/CXXTargets.cmake) + +## +## Project Setup +## +add_library(${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + DEBUG_POSTFIX d + POSITION_INDEPENDENT_CODE ON +) + +target_sources(${PROJECT_NAME} + PRIVATE + src/CGraph.cpp +) +target_include_directories(${PROJECT_NAME} + PUBLIC + ../cclCommons/include + include + PRIVATE + header + import/include +) +target_link_libraries(${PROJECT_NAME} + PRIVATE + ccl_CXXwarnings + ccl_CXXoptions +) + +if(MSVC) + if (CMAKE_BUILD_TYPE EQUAL "DEBUG") + set(LIB_SUFFIX d) + else() + set(LIB_SUFFIX "") + endif () + + set_target_properties(${PROJECT_NAME} + PROPERTIES + COMPILE_PDB_NAME ${PROJECT_NAME}${LIB_SUFFIX} + ) + + get_target_property(output_dir ${PROJECT_NAME} BINARY_DIR) + install(FILES ${output_dir}/$/${PROJECT_NAME}${LIB_SUFFIX}.pdb DESTINATION lib) +endif() + +install(TARGETS ${PROJECT_NAME} + ARCHIVE + DESTINATION lib + LIBRARY + DESTINATION lib + INCLUDES + DESTINATION include +) +install(DIRECTORY include/ DESTINATION include) + +if(CC_BuildTests) + enable_testing() + add_subdirectory("test") +endif() \ No newline at end of file diff --git a/ccl/cclGraph/cclGraph.vcxproj b/ccl/cclGraph/cclGraph.vcxproj new file mode 100644 index 0000000..a6dc509 --- /dev/null +++ b/ccl/cclGraph/cclGraph.vcxproj @@ -0,0 +1,193 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + 16.0 + {7E1D5338-F819-4C96-B461-9EAAB8D02E1D} + StaticLibrary + Win32Proj + cclGraph + v143 + 10.0 + Unicode + + + + true + + + true + + + false + true + + + false + true + + + + + + + + + + true + $(ProjectName)d + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + + + true + $(ProjectName)d + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + + + false + $(ProjectName) + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + + + false + $(ProjectName) + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + + + + NotUsing + Level4 + Disabled + true + _LIB;_DEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include;header + $(IntDir)$(ProjectName)d.pdb + $(IntDir)obj\ + Disabled + + + Windows + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + NotUsing + Level4 + Disabled + true + _LIB;_DEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include + $(IntDir)$(ProjectName)d.pdb + $(IntDir)obj\ + Disabled + + + Windows + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + NotUsing + Level4 + MaxSpeed + true + true + true + _LIB;NDEBUG;%(PreprocessorDefinitions) + true + + + stdcpplatest + true + true + include;header + $(IntDir)obj\ + + + Windows + true + true + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + + + NotUsing + Level4 + MaxSpeed + true + true + true + _LIB;NDEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include + $(IntDir)obj\ + + + Windows + true + true + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + \ No newline at end of file diff --git a/ccl/cclGraph/cclGraph.vcxproj.filters b/ccl/cclGraph/cclGraph.vcxproj.filters new file mode 100644 index 0000000..24815cc --- /dev/null +++ b/ccl/cclGraph/cclGraph.vcxproj.filters @@ -0,0 +1,26 @@ + + + + + + + + + {f0a3dd37-e5ae-4a37-ab65-d574c8dfe252} + + + + + Graph + + + + + + Graph + + + + + + \ No newline at end of file diff --git a/ccl/cclGraph/conanfile.txt b/ccl/cclGraph/conanfile.txt new file mode 100644 index 0000000..a345ddf --- /dev/null +++ b/ccl/cclGraph/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +gtest/1.14.0 + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout \ No newline at end of file diff --git a/ccl/cclGraph/include/ccl/Entity.hpp b/ccl/cclGraph/include/ccl/Entity.hpp new file mode 100644 index 0000000..d1ba390 --- /dev/null +++ b/ccl/cclGraph/include/ccl/Entity.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ccl { +//! Entity identifier +using EntityUID = uint32_t; + +//! Unordered set of entities +using SetOfEntities = std::unordered_set; + +//! Ordered vector of entities +using VectorOfEntities = std::vector; + +class EntityTranslation { + using Container = std::unordered_map; + Container relations{}; + +public: + using ConstIter = typename Container::const_iterator; + using size_type = typename Container::size_type; + + [[nodiscard]] ConstIter begin() const noexcept { + return std::begin(relations); + } + [[nodiscard]] ConstIter end() const noexcept { + return std::end(relations); + } + [[nodiscard]] size_type size() const noexcept { + return std::size(relations); + } + [[nodiscard]] bool empty() const noexcept { + return std::empty(relations); + } + + void Clear() noexcept { + relations.clear(); + } + [[nodiscard]] bool ContainsValue(const EntityUID value) const { + return std::any_of(begin(), end(), [&](const auto& el) { return el.second == value; }); + } + [[nodiscard]] bool ContainsKey(const EntityUID key) const { + return relations.contains(key); + } + [[nodiscard]] EntityUID operator()(const EntityUID key) const { + return relations.at(key); + } + void SubstituteValues(const EntityTranslation& substitutes) { + for (const auto& [key, value] : relations) { + if (substitutes.ContainsKey(value)) { + relations[key] = substitutes(value); + } + } + } + + // Note: doesn't break iterators! + void ReplaceValue(const EntityUID& key, const EntityUID& newVal) { + relations[key] = newVal; + } + + // Note: can break iterators! + void Insert(EntityUID key, EntityUID val) { + relations.emplace(key, val); + } + void Erase(EntityUID key) noexcept { + relations.erase(key); + } + + void SuperposeWith(const EntityTranslation& second) { + SubstituteValues(second); + for (const auto& iter : second.relations) { + if (!relations.contains(iter.first)) { + relations.insert(iter); + } + } + } + + [[nodiscard]] bool operator==(const EntityTranslation& second) const { + return relations == second.relations; + } + [[nodiscard]] bool operator!=(const EntityTranslation& second) const { + return relations != second.relations; + } +}; + +} // namespace ccl + +namespace ccl::tag { + +using Func_Name2UID = std::function(const std::string&)>; +using Func_UID2Name = std::function(EntityUID)>; + +} // namespace ccl::tag \ No newline at end of file diff --git a/ccl/cclGraph/include/ccl/graph/CGraph.h b/ccl/cclGraph/include/ccl/graph/CGraph.h new file mode 100644 index 0000000..9b498d9 --- /dev/null +++ b/ccl/cclGraph/include/ccl/graph/CGraph.h @@ -0,0 +1,95 @@ +#pragma once + +#include "ccl/Entity.hpp" + +#include +#include + +namespace ccl::graph { + +using VertexIndex = int32_t; + +//! Entity connections graph +class CGraph { + struct Vertex { + EntityUID uid{}; + bool isValid{ true }; + std::vector inputs{}; + std::vector outputs{}; + + Vertex() = default; + explicit constexpr Vertex(const EntityUID uid) : uid{ uid } {} + }; + + std::vector graph{}; + std::unordered_map verticies{}; + +public: + using UnorderedItems = SetOfEntities; + using OrderedItems = VectorOfEntities; + using ItemsGroup = std::vector; + + void Clear() noexcept; + + [[nodiscard]] bool Contains(EntityUID item) const; + [[nodiscard]] bool ConnectionExists(EntityUID source, EntityUID dest) const; + + [[nodiscard]] VertexIndex ItemsCount() const noexcept; + [[nodiscard]] VertexIndex ConnectionsCount() const; + + void AddItem(EntityUID item); + void EraseItem(EntityUID item); + + void AddConnection(EntityUID source, EntityUID dest); + void SetItemInputs(EntityUID item, const UnorderedItems& connectedItems); + [[nodiscard]] UnorderedItems InputsFor(EntityUID item) const; + + [[nodiscard]] bool IsReachableFrom(EntityUID dest, EntityUID source) const; + [[nodiscard]] bool HasLoop() const; + [[nodiscard]] ItemsGroup GetAllLoopsItems() const; + + [[nodiscard]] UnorderedItems ExpandOutputs(const UnorderedItems& input) const; + [[nodiscard]] UnorderedItems ExpandInputs(const UnorderedItems& input) const; + + [[nodiscard]] OrderedItems TopologicalOrder() const; + [[nodiscard]] OrderedItems InverseTopologicalOrder() const; + [[nodiscard]] OrderedItems Sort(const UnorderedItems& input) const; + +private: + [[nodiscard]] VertexIndex IndexFor(EntityUID uid) const; + + VertexIndex AddInternal(EntityUID item); + VertexIndex EraseInternal(EntityUID item); + + [[nodiscard]] bool HasEdge(VertexIndex source, VertexIndex destination) const; + [[nodiscard]] std::vector InternalOrder() const; +}; + +template +void TopologicalSort(const CGraph& graph, InputIt start, InputIt end, OutputIt inserter) { + if (start != end) { + for (const auto v : graph.TopologicalOrder()) { + if (std::find(start, end, v) != end) { + inserter = v; + } + } + } +} + +//! Updatable entity connections graph +class UpdatableGraph : public CGraph { + std::function updater; + bool invalid{ false }; + +public: + explicit UpdatableGraph(std::function externalUpdater); + +public: + void Invalidate() noexcept { invalid = true; } + void SetValid() noexcept { invalid = false; } + [[nodiscard]] bool IsBroken() const noexcept { return invalid; } + + void UpdateFor(EntityUID item); +}; + +} // namespace ccl::graph \ No newline at end of file diff --git a/ccl/cclGraph/src/CGraph.cpp b/ccl/cclGraph/src/CGraph.cpp new file mode 100644 index 0000000..1bab70a --- /dev/null +++ b/ccl/cclGraph/src/CGraph.cpp @@ -0,0 +1,332 @@ +#include "ccl/graph/CGraph.h" + +#include +#include + + // Disable warnings about using operator[] +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26446 ) +#endif + +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-conversion" +#endif + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +namespace ccl::graph { + +void CGraph::Clear() noexcept { + graph.clear(); + verticies.clear(); +} + +bool CGraph::Contains(const EntityUID item) const { + return verticies.contains(item); +} + +VertexIndex CGraph::IndexFor(const EntityUID uid) const { + return verticies.at(uid); +} + +void CGraph::AddItem(const EntityUID item) { + AddInternal(item); +} + +VertexIndex CGraph::AddInternal(const EntityUID item) { + if (!Contains(item)) { + graph.emplace_back(item); + const auto index = static_cast(size(graph) - 1); + verticies.emplace(item, index); + return index; + } else { + return IndexFor(item); + } +} + +bool CGraph::ConnectionExists(const EntityUID source, const EntityUID dest) const { + return Contains(source) && Contains(dest) && + HasEdge(IndexFor(source), IndexFor(dest)); +} + +bool CGraph::HasEdge(const VertexIndex source, const VertexIndex destination) const { + const auto& outputs = graph[source].outputs; + return std::find(begin(outputs), end(outputs), destination) != end(outputs); +} + +void CGraph::AddConnection(const EntityUID source, const EntityUID dest) { + if (!ConnectionExists(source, dest)) { + const auto srcID = AddInternal(source); + const auto destID = AddInternal(dest); + graph[srcID].outputs.push_back(destID); + graph[destID].inputs.push_back(srcID); + } +} + +void CGraph::EraseItem(const EntityUID item) { + if (Contains(item)) { + EraseInternal(item); + } +} + +VertexIndex CGraph::EraseInternal(const EntityUID item) { + const auto itemID = IndexFor(item); + for (const auto destination : graph[itemID].outputs) { + auto& inputs = graph[destination].inputs; + inputs.erase(std::find(begin(inputs), end(inputs), itemID)); + } + for (const auto source : graph[itemID].inputs) { + auto& outputs = graph[source].outputs; + outputs.erase(std::find(begin(outputs), end(outputs), itemID)); + } + graph[itemID].isValid = false; + graph[itemID].inputs.clear(); + graph[itemID].outputs.clear(); + verticies.erase(item); + return itemID; +} + +VertexIndex CGraph::ItemsCount() const noexcept { + return static_cast(ssize(verticies)); +} + +void CGraph::SetItemInputs(const EntityUID item, const UnorderedItems& connectedItems) { + const auto itemID = AddInternal(item); + for (const auto source : graph[itemID].inputs) { + auto& outputs = graph[source].outputs; + outputs.erase(std::find(begin(outputs), end(outputs), itemID)); + } + graph[itemID].inputs.clear(); + + for (const auto uid : connectedItems) { + const auto srcID = AddInternal(uid); + graph[itemID].inputs.push_back(srcID); + graph[srcID].outputs.push_back(itemID); + } +} + +CGraph::UnorderedItems CGraph::InputsFor(const EntityUID item) const { + if (!Contains(item)) { + return UnorderedItems{}; + } else { + UnorderedItems result{}; + for (const auto index : graph[IndexFor(item)].inputs) { + result.emplace(graph[index].uid); + } + return result; + } +} + +VertexIndex CGraph::ConnectionsCount() const { + return std::accumulate(begin(graph), end(graph), 0, + [](const VertexIndex val, const Vertex& item) noexcept { return val + static_cast(ssize(item.outputs)); }); +} + +bool CGraph::HasLoop() const { + std::vector status(size(graph), 0); + std::vector toVisit{}; + + for (VertexIndex index = 0; index < ssize(graph); ++index) { + if (status[index] > 1) { + continue; + } + toVisit.push_back(index); + while (!empty(toVisit)) { + const auto item = toVisit.back(); + if (status[item] == 0) { + status[item] = 1; + for (const auto child : graph[item].outputs) { + if (status[child] == 1) { + return true; + } else if (status[child] == 0) { + toVisit.push_back(child); + } + } + } else { + toVisit.pop_back(); + status[item] = 2; + } + } + } + return false; +} + +bool CGraph::IsReachableFrom(const EntityUID dest, const EntityUID source) const { + if (ConnectionExists(source, dest)) { + return true; + } else if (source == dest) { + return false; + } else { + const auto reachables = ExpandOutputs({ source }); + return std::find(begin(reachables), end(reachables), dest) != end(reachables); + } +} + +CGraph::UnorderedItems CGraph::ExpandOutputs(const UnorderedItems& input) const { + std::vector toVisit{}; + std::vector marked(size(graph), false); + for (const auto uid : input) { + if (Contains(uid)) { + const auto index = IndexFor(uid); + marked[index] = true; + toVisit.push_back(index); + } + } + + UnorderedItems result{}; + while (!empty(toVisit)) { + const auto item = toVisit.back(); + toVisit.pop_back(); + result.emplace(graph[item].uid); + for (const auto child : graph[item].outputs) { + if (!marked[child]) { + marked[child] = true; + toVisit.push_back(child); + } + } + } + + return result; +} + +CGraph::UnorderedItems CGraph::ExpandInputs(const UnorderedItems& input) const { + std::vector toVisit{}; + std::vector marked(size(graph), false); + for (const auto uid : input) { + if (Contains(uid)) { + const auto index = IndexFor(uid); + marked[index] = true; + toVisit.push_back(index); + } + } + + UnorderedItems result{}; + while (!empty(toVisit)) { + const auto item = toVisit.back(); + toVisit.pop_back(); + result.emplace(graph[item].uid); + for (const auto child : graph[item].inputs) { + if (!marked[child]) { + marked[child] = true; + toVisit.push_back(child); + } + } + } + + return result; +} + +std::vector CGraph::InternalOrder() const { + std::vector outOrder{}; + outOrder.reserve(size(verticies)); + + std::vector toVisit{}; + std::vector status(size(graph), 0); + for (VertexIndex index = 0; index < ssize(graph); ++index) { + if (status[index] != 0 || !graph[index].isValid) { + continue; + } + toVisit.push_back(index); + while (!empty(toVisit)) { + const auto item = toVisit.back(); + if (status[item] == 0) { + status[item] = 1; + for (const auto child : graph[item].outputs) { + if (status[child] == 0) { + toVisit.push_back(child); + } + } + } else { + toVisit.pop_back(); + if (status[item] != 2) { + status[item] = 2; + outOrder.push_back(item); + } + } + } + } + return outOrder; +} + +CGraph::OrderedItems CGraph::InverseTopologicalOrder() const { + OrderedItems outOrder{}; + outOrder.reserve(size(verticies)); + for (const auto index : InternalOrder()) { + outOrder.push_back(graph[index].uid); + } + return outOrder; +} + +CGraph::OrderedItems CGraph::Sort(const UnorderedItems& input) const { + OrderedItems result{}; + TopologicalSort(*this, begin(input), end(input), std::back_inserter(result)); + return result; +} + +CGraph::OrderedItems CGraph::TopologicalOrder() const { + auto result = InverseTopologicalOrder(); + std::reverse(begin(result), end(result)); + return result; +} + +CGraph::ItemsGroup CGraph::GetAllLoopsItems() const { + ItemsGroup result{}; + + std::vector marked(size(graph), false); + std::vector toVisit{}; + std::vector component{}; + for (const auto index : InternalOrder()) { + if (marked[index]) { + continue; + } + component.clear(); + toVisit.push_back(index); + marked[index] = true; + while (!empty(toVisit)) { + const auto item = toVisit.back(); + toVisit.pop_back(); + component.push_back(item); + for (const auto child : graph[item].outputs) { + if (!marked[child]) { + toVisit.push_back(child); + marked[child] = true; + } + } + } + if (size(component) != 1 || HasEdge(index, index)) { + result.push_back({}); + result.back().reserve(size(component)); + for (const auto item : component) { + result.back().emplace(graph[item].uid); + } + } + } + return result; +} + +UpdatableGraph::UpdatableGraph(std::function externalUpdater) + : updater{ std::move(externalUpdater) } {} + +void UpdatableGraph::UpdateFor(const EntityUID item) { + if (!IsBroken()) { + SetItemInputs(item, updater(item)); + } +} + +} // namespace ccl::graph + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif \ No newline at end of file diff --git a/ccl/cclGraph/test/CMakeLists.txt b/ccl/cclGraph/test/CMakeLists.txt new file mode 100644 index 0000000..312f5c8 --- /dev/null +++ b/ccl/cclGraph/test/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.23) + +find_package(GTest REQUIRED) + +add_executable(cclGraph_Tests) +target_sources(cclGraph_Tests + PRIVATE + src/testConnectionsGraph.cpp +) +target_include_directories(cclGraph_Tests + PRIVATE + ../header + ../import/include + utils +) +target_link_libraries(cclGraph_Tests + PRIVATE + cclGraph + ccl_CXXwarnings + ccl_CXXoptions + GTest::gtest + GTest::gtest_main +) + +include(GoogleTest) +gtest_discover_tests(cclGraph_Tests) \ No newline at end of file diff --git a/ccl/cclGraph/test/cclGraphTest.vcxproj b/ccl/cclGraph/test/cclGraphTest.vcxproj new file mode 100644 index 0000000..4fdfedc --- /dev/null +++ b/ccl/cclGraph/test/cclGraphTest.vcxproj @@ -0,0 +1,215 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5A2501C1-FEFB-4B14-A94D-E8F19ADEA239} + Win32Proj + 10.0 + Application + v143 + Unicode + cclGraphTest + + + + true + + + true + + + true + + + true + + + + + + + + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + + + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + false + + + false + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + + + + + + + + + + + {7e1d5338-f819-4c96-b461-9eaab8d02e1d} + + + + + + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + ..\include;..\header;%(AdditionalIncludeDirectories) + Disabled + true + true + + + true + Console + cclGraphd.lib;%(AdditionalDependencies) + false + ..\..\..\output\lib\x86;%(AdditionalLibraryDirectories) + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + ..\include;..\header;%(AdditionalIncludeDirectories) + Disabled + false + true + true + + + true + Console + cclGraphd.lib;%(AdditionalDependencies) + false + ..\..\..\output\lib\x64;%(AdditionalLibraryDirectories) + + + + + NotUsing + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + ..\include;..\header;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + cclGraph.lib;%(AdditionalDependencies) + ..\..\..\output\lib\x86;%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration + + + true + + + + + NotUsing + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + ..\include;..\header;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + cclGraph.lib;%(AdditionalDependencies) + ..\..\..\output\lib\x64;%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration + false + + + true + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/ccl/cclGraph/test/cclGraphTest.vcxproj.filters b/ccl/cclGraph/test/cclGraphTest.vcxproj.filters new file mode 100644 index 0000000..2ffe2e8 --- /dev/null +++ b/ccl/cclGraph/test/cclGraphTest.vcxproj.filters @@ -0,0 +1,20 @@ + + + + + + + + + {ed04b33d-515f-46b0-aad1-54dcbc55a5fd} + + + + + src + + + + + + \ No newline at end of file diff --git a/ccl/cclGraph/test/packages.config b/ccl/cclGraph/test/packages.config new file mode 100644 index 0000000..be1fa03 --- /dev/null +++ b/ccl/cclGraph/test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ccl/cclGraph/test/src/testConnectionsGraph.cpp b/ccl/cclGraph/test/src/testConnectionsGraph.cpp new file mode 100644 index 0000000..4a5a4b6 --- /dev/null +++ b/ccl/cclGraph/test/src/testConnectionsGraph.cpp @@ -0,0 +1,350 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/graph/CGraph.h" + +#include + +class UTCGraph : public ::testing::Test { +protected: + using CGraph = ccl::graph::CGraph; + CGraph graph{}; + const ccl::VectorOfEntities uids{ 0, 1, 42, 3, 44, 5, 6, 7, 8, 9 }; + +protected: + void PrepareGraphForExpansion(); +}; + +void UTCGraph::PrepareGraphForExpansion() { + graph.AddConnection(uids[0], uids[0]); + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[0], uids[2]); + graph.AddConnection(uids[1], uids[3]); + graph.AddConnection(uids[3], uids[1]); + graph.AddConnection(uids[3], uids[4]); +} + +TEST_F(UTCGraph, ItemsCount) { + EXPECT_EQ(graph.ItemsCount(), 0); + graph.AddItem(uids[0]); + EXPECT_TRUE(graph.Contains(uids[0])); + EXPECT_EQ(graph.ItemsCount(), 1); +} + +TEST_F(UTCGraph, AddDuplicateItem) { + graph.AddItem(uids[0]); + EXPECT_TRUE(graph.Contains(uids[0])); + + graph.AddItem(uids[0]); + EXPECT_TRUE(graph.Contains(uids[0])); + EXPECT_EQ(graph.ItemsCount(), 1); +} + +TEST_F(UTCGraph, ForeignItem) { + graph.AddItem(uids[0]); + EXPECT_FALSE(graph.Contains(uids[1])); + EXPECT_TRUE(empty(graph.InputsFor(uids[1]))); + EXPECT_TRUE(empty(graph.ExpandOutputs({ uids[1] }))); + EXPECT_TRUE(empty(graph.ExpandInputs({ uids[1] }))); + + EXPECT_FALSE(graph.ConnectionExists(uids[1], uids[1])); + EXPECT_FALSE(graph.ConnectionExists(uids[0], uids[1])); + EXPECT_FALSE(graph.ConnectionExists(uids[1], uids[0])); + + EXPECT_FALSE(graph.IsReachableFrom(uids[1], uids[1])); + EXPECT_FALSE(graph.IsReachableFrom(uids[1], uids[0])); + EXPECT_FALSE(graph.IsReachableFrom(uids[0], uids[1])); +} + +TEST_F(UTCGraph, EmptyGroupInput) { + PrepareGraphForExpansion(); + EXPECT_TRUE(empty(graph.ExpandOutputs({}))); + EXPECT_TRUE(empty(graph.ExpandInputs({}))); +} + +TEST_F(UTCGraph, Clear) { + graph.AddItem(uids[0]); + EXPECT_TRUE(graph.Contains(uids[0])); + graph.Clear(); + EXPECT_FALSE(graph.Contains(uids[0])); +} + +TEST_F(UTCGraph, CopyAndMove) { + graph.AddItem(uids[0]); + CGraph copy{ graph }; + EXPECT_TRUE(copy.Contains(uids[0])); + copy.EraseItem(uids[0]); + EXPECT_FALSE(copy.Contains(uids[0])); + EXPECT_TRUE(graph.Contains(uids[0])); + + copy = graph; + EXPECT_TRUE(copy.Contains(uids[0])); + + CGraph moved(std::move(copy)); + EXPECT_TRUE(moved.Contains(uids[0])); + + CGraph secondMove{}; + secondMove = std::move(moved); + EXPECT_TRUE(secondMove.Contains(uids[0])); +} + +TEST_F(UTCGraph, AddConnection) { + graph.AddItem(uids[0]); + graph.AddItem(uids[1]); + EXPECT_EQ(ssize(graph.InputsFor(uids[0])), 0); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 0); + + graph.AddConnection(uids[0], uids[1]); + EXPECT_TRUE(graph.ConnectionExists(uids[0], uids[1])); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 1); + EXPECT_EQ(ssize(graph.InputsFor(uids[0])), 0); +} + +TEST_F(UTCGraph, ConnectionsCount) { + EXPECT_EQ(graph.ConnectionsCount(), 0); + graph.AddItem(uids[0]); + graph.AddItem(uids[1]); + graph.AddConnection(uids[0], uids[1]); + EXPECT_EQ(graph.ConnectionsCount(), 1); +} + +TEST_F(UTCGraph, AddDoubleConnection) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[0], uids[1]); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 1); + EXPECT_EQ(graph.ConnectionsCount(), 1); +} + +TEST_F(UTCGraph, AddSelfConnection) { + graph.AddConnection(uids[0], uids[0]); + EXPECT_EQ(ssize(graph.InputsFor(uids[0])), 1); + EXPECT_EQ(graph.ConnectionsCount(), 1); +} + +TEST_F(UTCGraph, AddBiConnection) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[0]); + EXPECT_TRUE(graph.ConnectionExists(uids[0], uids[1])); + EXPECT_TRUE(graph.ConnectionExists(uids[1], uids[0])); + EXPECT_EQ(ssize(graph.InputsFor(uids[0])), 1); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 1); + EXPECT_EQ(graph.ConnectionsCount(), 2); +} + +TEST_F(UTCGraph, AddConnectionWithItems) { + EXPECT_EQ(graph.ItemsCount(), 0); + + graph.AddConnection(uids[1], uids[0]); + EXPECT_EQ(ssize(graph.InputsFor(uids[0])), 1); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 0); + EXPECT_EQ(graph.ConnectionsCount(), 1); +} + +TEST_F(UTCGraph, CheckInvalidConnection) { + graph.AddConnection(uids[0], uids[1]); + EXPECT_TRUE(graph.ConnectionExists(uids[0], uids[1])); + EXPECT_FALSE(graph.ConnectionExists(uids[1], uids[0])); + EXPECT_FALSE(graph.ConnectionExists(uids[0], uids[0])); + EXPECT_FALSE(graph.ConnectionExists(uids[0], uids[2])); + EXPECT_FALSE(graph.ConnectionExists(uids[2], uids[0])); + EXPECT_FALSE(graph.ConnectionExists(uids[2], uids[3])); +} + +TEST_F(UTCGraph, EraseItem) { + graph.AddItem(uids[0]); + graph.AddItem(uids[1]); + graph.EraseItem(uids[0]); + EXPECT_EQ(graph.ItemsCount(), 1); + EXPECT_TRUE(graph.Contains(uids[1])); + EXPECT_FALSE(graph.Contains(uids[0])); + EXPECT_EQ(graph.ConnectionsCount(), 0); +} + +TEST_F(UTCGraph, EraseConnectedItem) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[0]); + graph.EraseItem(uids[0]); + EXPECT_EQ(graph.ItemsCount(), 1); + EXPECT_EQ(graph.ConnectionsCount(), 0); + EXPECT_EQ(ssize(graph.InputsFor(uids[1])), 0); + + graph.EraseItem(uids[1]); + EXPECT_EQ(graph.ItemsCount(), 0); + EXPECT_EQ(graph.ConnectionsCount(), 0); +} + +TEST_F(UTCGraph, SetConnections) { + graph.SetItemInputs(uids[0], { begin(uids), end(uids) }); + EXPECT_EQ(graph.ItemsCount(), ssize(uids)); + EXPECT_EQ(graph.ConnectionsCount(), ssize(uids)); +} + +TEST_F(UTCGraph, SetConnectionsWithPreexisting) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[0]); + graph.SetItemInputs(uids[0], { begin(uids), end(uids) }); + EXPECT_TRUE(graph.ConnectionExists(uids[0], uids[1])); + EXPECT_EQ(graph.ItemsCount(), ssize(uids)); + EXPECT_EQ(graph.ConnectionsCount(), ssize(uids) + 1); +} + +TEST_F(UTCGraph, SetConnectionsReplacing) { + graph.AddConnection(uids[2], uids[0]); + graph.AddConnection(uids[0], uids[0]); + graph.SetItemInputs(uids[0], { uids[1] }); + EXPECT_TRUE(graph.ConnectionExists(uids[1], uids[0])); + EXPECT_FALSE(graph.ConnectionExists(uids[2], uids[0])); + EXPECT_EQ(graph.ConnectionsCount(), 1); +} + +TEST_F(UTCGraph, EraseAfterSetConnections) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[0]); + graph.SetItemInputs(uids[0], { uids[2], uids[3] }); + graph.EraseItem(uids[1]); + EXPECT_EQ(graph.ConnectionsCount(), 2); +} + +TEST_F(UTCGraph, SimpleLoop) { + EXPECT_FALSE(graph.HasLoop()); + graph.AddConnection(uids[0], uids[0]); + EXPECT_TRUE(graph.HasLoop()); + bool loopFoundCorrect = graph.GetAllLoopsItems() == CGraph::ItemsGroup{ { uids[0] } }; + EXPECT_TRUE(loopFoundCorrect); +} + +TEST_F(UTCGraph, ComplexGraph) { + graph.AddItem(uids[1]); + graph.AddItem(uids[0]); + graph.AddItem(uids[9]); + graph.AddItem(uids[3]); + graph.AddItem(uids[8]); + graph.AddItem(uids[5]); + graph.AddItem(uids[2]); + graph.AddItem(uids[6]); + graph.AddItem(uids[4]); + graph.AddItem(uids[7]); + + graph.AddConnection(uids[2], uids[0]); + graph.AddConnection(uids[3], uids[0]); + graph.AddConnection(uids[3], uids[1]); + graph.AddConnection(uids[4], uids[3]); + graph.AddConnection(uids[4], uids[2]); + graph.AddConnection(uids[6], uids[3]); + graph.AddConnection(uids[6], uids[4]); + graph.AddConnection(uids[6], uids[2]); + graph.AddConnection(uids[7], uids[6]); + graph.AddConnection(uids[7], uids[5]); + graph.AddConnection(uids[5], uids[0]); + graph.AddConnection(uids[5], uids[3]); + graph.AddConnection(uids[8], uids[5]); + graph.AddConnection(uids[8], uids[7]); + graph.AddConnection(uids[9], uids[3]); + graph.AddConnection(uids[9], uids[5]); + graph.AddConnection(uids[9], uids[8]); + + EXPECT_FALSE(graph.IsReachableFrom(uids[0], uids[1])); + EXPECT_FALSE(graph.IsReachableFrom(uids[1], uids[0])); + EXPECT_FALSE(graph.HasLoop()); +} + +TEST_F(UTCGraph, ComplexLoop) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[2]); + graph.AddConnection(uids[2], uids[0]); + graph.AddConnection(uids[2], uids[3]); + ASSERT_TRUE(graph.HasLoop()); + + const std::vector loop{ { uids[0], uids[1], uids[2] } }; + EXPECT_EQ(graph.GetAllLoopsItems(), loop); +} + +TEST_F(UTCGraph, MultipleLoops) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[2]); + graph.AddConnection(uids[2], uids[0]); + graph.AddConnection(uids[2], uids[3]); + graph.AddConnection(uids[3], uids[3]); + ASSERT_TRUE(graph.HasLoop()); + + auto loopsItems = graph.GetAllLoopsItems(); + ASSERT_EQ(ssize(loopsItems), 2); + const auto loop1 = CGraph::ItemsGroup::value_type{ uids[0], uids[1], uids[2] }; + const auto loop2 = CGraph::ItemsGroup::value_type{ uids[3] }; + + EXPECT_TRUE((loopsItems[0] == loop1 && loopsItems[1] == loop2) || + (loopsItems[1] == loop1 && loopsItems[0] == loop2)); +} + +TEST_F(UTCGraph, IsReachableFrom) { + PrepareGraphForExpansion(); + EXPECT_TRUE(graph.IsReachableFrom(uids[0], uids[0])); + EXPECT_FALSE(graph.IsReachableFrom(uids[4], uids[4])); + EXPECT_TRUE(graph.IsReachableFrom(uids[1], uids[0])); + EXPECT_FALSE(graph.IsReachableFrom(uids[0], uids[1])); + EXPECT_TRUE(graph.IsReachableFrom(uids[4], uids[0])); +} + +TEST_F(UTCGraph, ExpandOutputs) { + PrepareGraphForExpansion(); + auto expansion = graph.ExpandOutputs({ uids[0] }); + ccl::SetOfEntities testingVector{ uids[0], uids[1], uids[2], uids[3], uids[4] }; + EXPECT_EQ(expansion, testingVector); + for (const auto id : expansion) { + if (id != uids[0]) { + EXPECT_TRUE(graph.IsReachableFrom(id, uids[0])); + } + } +} + +TEST_F(UTCGraph, ExpandIntoReachableReverse) { + PrepareGraphForExpansion(); + auto expansion = graph.ExpandInputs({ uids[4] }); + ccl::SetOfEntities testingVector{ uids[0], uids[1], uids[3], uids[4] }; + EXPECT_EQ(expansion, testingVector); +} + +TEST_F(UTCGraph, InverseTopologicalOrder) { + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[0], uids[2]); + graph.AddConnection(uids[2], uids[1]); + graph.AddConnection(uids[4], uids[3]); + graph.AddItem(uids[5]); + + auto sorted = graph.InverseTopologicalOrder(); + ASSERT_FALSE(empty(sorted)); + for (auto i = 0U; i < size(sorted) - 1; ++i) { + for (auto j = i + 1; j < size(sorted); ++j) { + EXPECT_FALSE(graph.IsReachableFrom(sorted[j], sorted[i])); + } + } +} + +TEST_F(UTCGraph, TopologicalOrder) { + EXPECT_TRUE(empty(graph.TopologicalOrder())); + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[0], uids[2]); + graph.AddConnection(uids[2], uids[1]); + graph.AddConnection(uids[4], uids[3]); + graph.AddItem(uids[5]); + + auto sorted = graph.TopologicalOrder(); + ASSERT_FALSE(empty(sorted)); + for (auto i = 0U; i < size(sorted) - 1; ++i) { + for (auto j = i + 1; j < size(sorted); ++j) { + EXPECT_FALSE(graph.IsReachableFrom(sorted[i], sorted[j])); + } + } +} + +TEST_F(UTCGraph, InverseTopologicalOrderLoop) { + EXPECT_TRUE(empty(graph.InverseTopologicalOrder())); + graph.AddConnection(uids[0], uids[1]); + graph.AddConnection(uids[1], uids[2]); + graph.AddConnection(uids[2], uids[0]); + graph.AddConnection(uids[3], uids[0]); + auto sorted = graph.InverseTopologicalOrder(); + EXPECT_TRUE(std::find(begin(sorted), end(sorted), uids[3]) > + std::find(begin(sorted), end(sorted), uids[0])); +} \ No newline at end of file diff --git a/ccl/cclLang/CMakeLists.txt b/ccl/cclLang/CMakeLists.txt new file mode 100644 index 0000000..8c09978 --- /dev/null +++ b/ccl/cclLang/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 3.23) + +project (cclLang VERSION 1.2.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +## +## Project options +## +option(CC_BuildTests "Include tests executable" TRUE) +option(CC_UseSanitizers "Use sanitizers" FALSE) + +## Compiler options +include(../cmake/CXXTargets.cmake) + +## +## Project Setup +## +add_library(${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + DEBUG_POSTFIX d + POSITION_INDEPENDENT_CODE ON +) + +target_sources(${PROJECT_NAME} + PRIVATE + unity/cclLang.cpp +) +target_include_directories(${PROJECT_NAME} + PUBLIC + ../cclCommons/include + include + PRIVATE + header + import/include +) +target_link_libraries(${PROJECT_NAME} + PRIVATE + ccl_CXXwarnings + ccl_CXXoptions +) + +if(MSVC) + if (CMAKE_BUILD_TYPE EQUAL "DEBUG") + set(LIB_SUFFIX d) + else() + set(LIB_SUFFIX "") + endif () + + set_target_properties(${PROJECT_NAME} + PROPERTIES + COMPILE_PDB_NAME ${PROJECT_NAME}${LIB_SUFFIX} + ) + + get_target_property(output_dir ${PROJECT_NAME} BINARY_DIR) + install(FILES ${output_dir}/$/${PROJECT_NAME}${LIB_SUFFIX}.pdb DESTINATION lib) +endif() + +install(TARGETS ${PROJECT_NAME} + ARCHIVE + DESTINATION lib + LIBRARY + DESTINATION lib + INCLUDES + DESTINATION include +) +install(DIRECTORY include/ DESTINATION include) + +if(CC_BuildTests) + enable_testing() + add_subdirectory("test") +endif() \ No newline at end of file diff --git a/ccl/cclLang/cclLang.vcxproj b/ccl/cclLang/cclLang.vcxproj new file mode 100644 index 0000000..e95b490 --- /dev/null +++ b/ccl/cclLang/cclLang.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + 16.0 + StaticLibrary + {76B03803-56CC-47C2-A8F0-2241FCAF2898} + Win32Proj + cclLang + v143 + 10.0 + Unicode + + + + true + + + true + + + false + true + + + false + true + + + + + + + + + + + + true + $(ProjectName)d + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + + + true + $(ProjectName)d + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + + + false + $(ProjectName) + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + + + false + $(ProjectName) + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + + + + NotUsing + Level4 + Disabled + true + _LIB;_DEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include;header;..\cclCommons\include + $(IntDir)$(ProjectName)d.pdb + $(IntDir)obj\ + Disabled + + + Windows + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + NotUsing + Level4 + Disabled + true + _LIB;_DEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include;header;..\cclCommons\include + $(IntDir)$(ProjectName)d.pdb + $(IntDir)obj\ + Disabled + false + + + Windows + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + NotUsing + Level4 + MaxSpeed + true + true + true + _LIB;NDEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include;header;..\cclCommons\include + $(IntDir)obj\ + + + Windows + true + true + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + + + NotUsing + Level4 + MaxSpeed + true + true + true + _LIB;NDEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + true + true + include;header;..\cclCommons\include + $(IntDir)obj\ + + + Windows + true + true + true + + + xcopy /y /s /q /i include ..\..\output\include +xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include + + + + + \ No newline at end of file diff --git a/ccl/cclLang/cclLang.vcxproj.filters b/ccl/cclLang/cclLang.vcxproj.filters new file mode 100644 index 0000000..eb8c9f5 --- /dev/null +++ b/ccl/cclLang/cclLang.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {3c85ab44-bb88-4509-be90-8f248199ac3f} + + + {5ea8ccaf-0a49-441e-8a3a-bb300790ffa4} + + + + + lang + + + lang + + + lang + + + lang + + + lang + + + env + + + env + + + lang + + + lang + + + + + lang + + + lang + + + lang + + + lang + + + env + + + env + + + lang + + + lang + + + \ No newline at end of file diff --git a/ccl/cclLang/conanfile.txt b/ccl/cclLang/conanfile.txt new file mode 100644 index 0000000..a345ddf --- /dev/null +++ b/ccl/cclLang/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +gtest/1.14.0 + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/EntityTermContext.hpp b/ccl/cclLang/include/ccl/lang/EntityTermContext.hpp new file mode 100644 index 0000000..802c0ad --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/EntityTermContext.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "ccl/lang/Morphology.h" + +#include +#include +#include + +namespace ccl::lang { + +class LexicalTerm; + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +//! Term context +class EntityTermContext { +public: + virtual ~EntityTermContext() noexcept = default; + +protected: + EntityTermContext() = default; + EntityTermContext(const EntityTermContext&) = default; + EntityTermContext& operator=(const EntityTermContext&) = default; + EntityTermContext(EntityTermContext&&) noexcept = default; + EntityTermContext& operator=(EntityTermContext&&) noexcept = default; + +public: + [[nodiscard]] virtual const LexicalTerm* At(const std::string& /*entity*/) const { + return nullptr; + } + [[nodiscard]] virtual bool Contains(const std::string& /*entity*/) const { + return false; + } + + [[nodiscard]] virtual std::unordered_map + MatchingTerms(const std::string& /*input*/) const { + return {}; + } +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/LexicalTerm.h b/ccl/cclLang/include/ccl/lang/LexicalTerm.h new file mode 100644 index 0000000..e35fda6 --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/LexicalTerm.h @@ -0,0 +1,59 @@ +#pragma once + +#include "ccl/lang/Morphology.h" +#include "ccl/lang/ManagedText.h" + +#include + +namespace ccl::lang { + +class EntityTermContext; + +//! Complex term with managed text and cached resolution +class LexicalTerm { + using Forms = std::unordered_map; + + ManagedText text{}; + + Forms manualForms{}; + mutable Forms cachedForms{}; + +public: + LexicalTerm() noexcept = default; + explicit LexicalTerm(std::string ref, std::string resolved) noexcept + : text{ ManagedText(std::move(ref), std::move(resolved)) } {} + explicit LexicalTerm(std::string ref) noexcept + : text{ std::move(ref) } {} + explicit LexicalTerm(ManagedText txt) noexcept + : text{ std::move(txt) } {} + +public: + [[nodiscard]] const std::string& Nominal() const noexcept { + return text.Str(); + } + [[nodiscard]] const ManagedText& Text() const noexcept { + return text; + } + void SetText(std::string_view ref, const EntityTermContext& cntxt); + void TranslateRefs(const StrTranslator& old2New, const EntityTermContext& cntxt); + void TranslateRaw(const StrTranslator& old2New); + + [[nodiscard]] bool operator==(const LexicalTerm& t2) const noexcept; + [[nodiscard]] bool operator!=(const LexicalTerm& t2) const noexcept { return !(*this == t2); } + + void UpdateFrom(const EntityTermContext& cntxt); + + [[nodiscard]] bool MatchStr(const std::string& str) const; + + [[nodiscard]] const std::string& GetForm(const Morphology& form) const; + [[nodiscard]] const std::string& GetNominalForm() const; + [[nodiscard]] const std::unordered_map& GetAllManual() const; + + void SetForm(const Morphology& form, std::string_view formText); + [[nodiscard]] bool IsFormManual(const Morphology& form) const; + [[nodiscard]] const std::string& GetManualForm(const Morphology& form) const; + + void ClearForms() noexcept; +}; + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/Literals.h b/ccl/cclLang/include/ccl/lang/Literals.h new file mode 100644 index 0000000..360c61f --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/Literals.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ccl/lang/Morphology.h" +#include "ccl/lang/Reference.h" + +namespace ccl::lang { + +//! Morphology from string of comma separated tags +Morphology operator""_form(const char* input, size_t /*size*/); + +//! Reference from string +Reference operator""_ref(const char* input, size_t /*size*/); + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/ManagedText.h b/ccl/cclLang/include/ccl/lang/ManagedText.h new file mode 100644 index 0000000..c950f52 --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/ManagedText.h @@ -0,0 +1,41 @@ +#pragma once + +#include "ccl/Substitutes.hpp" +#include "ccl/lang/Reference.h" + +#include + +namespace ccl::lang { + +class EntityTermContext; + +//! Text with managed references +class ManagedText { + std::string rawText{}; + mutable std::string cache{}; + +public: + ManagedText() noexcept = default; + explicit ManagedText(std::string stringWithRefs, std::string cache) noexcept + : rawText{ std::move(stringWithRefs) }, cache{ std::move(cache) } {} + explicit ManagedText(std::string stringWithRefs) noexcept + : ManagedText(std::move(stringWithRefs), std::string{}) {} + +public: + [[nodiscard]] bool operator==(const ManagedText& str2) const noexcept; + [[nodiscard]] bool operator!=(const ManagedText& str2) const noexcept; + [[nodiscard]] bool empty() const noexcept; + [[nodiscard]] const std::string& Str() const noexcept; + [[nodiscard]] const std::string& Raw() const noexcept; + + void SetRaw(std::string_view ref); + void InitFrom(std::string_view ref, const EntityTermContext& cntxt); + void UpdateFrom(const EntityTermContext& cntxt); + + void TranslateRaw(const StrTranslator& old2New); + void TranslateRefs(const StrTranslator& old2New, const EntityTermContext& cntxt); + + [[nodiscard]] std::unordered_set Referals() const; +}; + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/Morphology.h b/ccl/cclLang/include/ccl/lang/Morphology.h new file mode 100644 index 0000000..78bf6ed --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/Morphology.h @@ -0,0 +1,191 @@ +#pragma once + +#include +#include +#include + +#include "ccl/cclTypes.hpp" + +//! Namespace for russian language specification +namespace ccl::lang { + +//! All values of morphology attributes +enum class Grammem : uint8_t { + invalid = 0, + NOUN, NPRO, INFN, VERB, ADJF, ADJS, PRTF, PRTS, ADVB, GRND, COMP, PRED, NUMR, + CONJ, INTJ, PRCL, PREP, PNCT, + pres, past, futr, + per1, per2, per3, + sing, plur, + masc, femn, neut, + nomn, gent, datv, ablt, accs, loct + +}; + +namespace detail { +static constexpr size_t GRAMMEM_LENGTH = 4U; +static constexpr std::array TAG_NAMES = { + "UNKN", + "NOUN", "NPRO", "INFN", "VERB", "ADJF", "ADJS", + "PRTF", "PRTS", "ADVB", "GRND", "COMP", "PRED", + "NUMR", "CONJ", "INTJ", "PRCL", "PREP", "PNCT", + "pres", "past", "futr", + "1per", "2per", "3per", + "sing", "plur", + "masc", "femn", "neut", + "nomn", "gent", "datv", "ablt", "accs", "loct" +}; + +static constexpr size_t GRAMMEM_COUNT = 36U; +using MapType = StaticMap; +using MapValue = MapType::DataType::value_type; +static constexpr MapType TAG_MAP{ + MapType::DataType({ + MapValue{"UNKN", Grammem::invalid}, + MapValue{"NOUN", Grammem::NOUN}, MapValue{"NPRO", Grammem::NPRO}, MapValue{"INFN", Grammem::INFN}, + MapValue{"VERB", Grammem::VERB}, MapValue{"ADJF", Grammem::ADJF}, MapValue{"ADJS", Grammem::ADJS}, + MapValue{"PRTF", Grammem::PRTF}, MapValue{"PRTS", Grammem::PRTS}, MapValue{"ADVB", Grammem::ADVB}, + MapValue{"GRND", Grammem::GRND}, MapValue{"COMP", Grammem::COMP}, MapValue{"PRED", Grammem::PRED}, + MapValue{"NUMR", Grammem::NUMR}, MapValue{"CONJ", Grammem::CONJ}, MapValue{"INTJ", Grammem::INTJ}, + MapValue{"PRCL", Grammem::PRCL}, MapValue{"PREP", Grammem::PREP}, MapValue{"PNCT", Grammem::PNCT}, + MapValue{"1per", Grammem::per1}, MapValue{"2per", Grammem::per2}, MapValue{"3per", Grammem::per3}, + MapValue{"pres", Grammem::pres}, MapValue{"past", Grammem::past}, MapValue{"futr", Grammem::futr}, + MapValue{"sing", Grammem::sing}, MapValue{"plur", Grammem::plur}, + MapValue{"masc", Grammem::masc}, MapValue{"femn", Grammem::femn}, MapValue{"neut", Grammem::neut}, + MapValue{"nomn", Grammem::nomn}, MapValue{"gent", Grammem::gent}, MapValue{"datv", Grammem::datv}, + MapValue{"ablt", Grammem::ablt}, MapValue{"accs", Grammem::accs}, MapValue{"loct", Grammem::loct} + }) +}; + +} // namespace detail + +[[nodiscard]] inline Grammem Str2Grammem(std::string_view text) { + if (text.length() != detail::GRAMMEM_LENGTH || !detail::TAG_MAP.ContainsKey(text)) { + return Grammem::invalid; + } else { + return detail::TAG_MAP.AtKey(text); + } +} + +[[nodiscard]] inline std::string_view Grammem2Str(Grammem gram) noexcept { + return detail::TAG_NAMES.at(static_cast(gram)); +} + +//! Morphology parameters for a word or collation of words +struct Morphology { + std::set tags{}; + + Morphology() = default; + explicit Morphology(std::initializer_list init) noexcept // NOLINT + : tags{ init } {} + explicit Morphology(std::string_view tagsText); + explicit Morphology(const std::vector& tags_); + + [[nodiscard]] bool operator==(const Morphology& rval) const noexcept; + [[nodiscard]] bool operator!=(const Morphology& rval) const noexcept; + + [[nodiscard]] size_t size() const noexcept; + [[nodiscard]] bool empty() const noexcept; + [[nodiscard]] bool Contains(Grammem gram) const noexcept; + + [[nodiscard]] Grammem GetPOS() const; + [[nodiscard]] Grammem GetCase() const; + [[nodiscard]] Grammem GetNumber() const; + [[nodiscard]] Grammem GetGender() const; + [[nodiscard]] Grammem GetTense() const; + [[nodiscard]] Grammem GetPerson() const; + + [[nodiscard]] std::string ToString() const noexcept; +}; + +//! Часть речи +static constexpr std::array ALL_POS = { + Grammem::NOUN, // существительное | хомяк + Grammem::NPRO, // местоимение | он + Grammem::INFN, // глагол (инфинитив) | говорить + Grammem::VERB, // глагол (личная форма) | говорил + Grammem::ADJF, // прилагательное (полное) | хороший + Grammem::ADJS, // прилагательное (краткое) | хорош + Grammem::PRTF, // причастие (полное) | прочитавший, прочитанная + Grammem::PRTS, // причастие (краткое) | прочитана + Grammem::ADVB, // наречие | далеко + Grammem::GRND, // деепричастие | прочитав + Grammem::COMP, // компаратив | лучше, получше, выше + Grammem::PRED, // предикатив | некогда + Grammem::NUMR, // числительное | три + Grammem::CONJ, // союз | или + Grammem::INTJ, // междометие | ой + Grammem::PRCL, // частица | бы, же + Grammem::PREP, // предлог | в + Grammem::PNCT // знак пунктуации +}; + +//! Падеж +static constexpr std::array ALL_CASES = { + Grammem::nomn, // именительный | Кто?, Что? | (хомяк) ест + Grammem::gent, // родительный | Кого? Чего? | у нас нет (хомяка) + Grammem::datv, // дательный | Кому? Чему? | сказать (хомяку) спасибо + Grammem::ablt, // винительный | Кого? Что? | тигр ест (хомяка) + Grammem::accs, // творительный | Кем? Чем? | зерно съедено (хомяком) + Grammem::loct // предложный | О ком? О чём? | хомяка несут в (коробке) +}; + +//! Число +static constexpr std::array ALL_NUMBERS = { + Grammem::sing, // единственное + Grammem::plur // множественное +}; + +//! Род +static constexpr std::array ALL_GENDERS = { + Grammem::masc, // мужской + Grammem::femn, // женский + Grammem::neut // средний +}; + +//! Время +static constexpr std::array ALL_TENSES = { + Grammem::pres, // настоящее + Grammem::past, // прошлое + Grammem::futr // будущее +}; + +//! Лицо +static constexpr std::array ALL_PERSONS = { + Grammem::per1, // первое (я, мы) + Grammem::per2, // второе (ты, вы) + Grammem::per3 // третье (он, она, оно, они) +}; + +//! Словоформы терминологической связки +static const std::array TERM_FORMS = { + // TODO: replace static object for constexpr. Need to figure out constexpr Morphology + Morphology{ Grammem::sing, Grammem::nomn }, + Morphology{ Grammem::sing, Grammem::gent }, + Morphology{ Grammem::sing, Grammem::datv }, + Morphology{ Grammem::sing, Grammem::ablt }, + Morphology{ Grammem::sing, Grammem::accs }, + Morphology{ Grammem::sing, Grammem::loct }, + Morphology{ Grammem::plur, Grammem::nomn }, + Morphology{ Grammem::plur, Grammem::gent }, + Morphology{ Grammem::plur, Grammem::datv }, + Morphology{ Grammem::plur, Grammem::ablt }, + Morphology{ Grammem::plur, Grammem::accs }, + Morphology{ Grammem::plur, Grammem::loct }, +}; + +} // namespace ccl::lang + +namespace std { +template <> +struct hash { + uint32_t operator()(const ccl::lang::Morphology& form) const noexcept { + using std::hash; + uint32_t result = 0; + for (const auto tag : form.tags) { + result += static_cast(tag); + } + return result + 0xFF * static_cast(size(form.tags)); // NOLINT + } +}; +} // namespace std \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/Reference.h b/ccl/cclLang/include/ccl/lang/Reference.h new file mode 100644 index 0000000..61ed604 --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/Reference.h @@ -0,0 +1,94 @@ +#pragma once + +#include "ccl/Strings.hpp" +#include "ccl/cclMeta.hpp" +#include "ccl/Substitutes.hpp" +#include "ccl/lang/EntityTermContext.hpp" + +#include +#include +#include + +namespace ccl::lang { + +//! Reference types +enum class ReferenceType : uint8_t { + invalid = 0, + entity, + collaboration +}; + +//! Reference to entitity in a specific form +struct EntityRef { + std::string entity; + Morphology form; + + explicit EntityRef(std::string entity, Morphology form) noexcept + : entity{ std::move(entity) }, form{ std::move(form)} {} + + enum Fields : uint8_t { + TR_ENTITY = 0, + TR_TAGS = 1 + }; + static constexpr uint8_t fieldCount = 2; + + [[nodiscard]] std::string ToString() const; +}; + +//! Reference to a text in collaboration with another reference +struct CollaborationRef { + std::string nominal; + int16_t offset; + + explicit CollaborationRef(std::string text, int16_t offset) noexcept + : nominal{ std::move(text) }, offset{ offset } {} + + enum Fields : uint8_t { + CR_OFFSET = 0, + CR_TEXT = 1 + }; + static constexpr uint8_t fieldCount = 2; + + [[nodiscard]] std::string ToString() const; +}; + +//! Reference facade +class Reference { + using ReferenceData = std::variant; + ReferenceData data{}; + ReferenceType type{ ReferenceType::invalid }; + +public: + StrRange position{}; + std::string resolvedText{}; + +public: + Reference() noexcept = default; + explicit Reference(EntityRef data, StrRange position_ = {}) noexcept + : data{ std::move(data) }, type{ ReferenceType::entity }, position{ position_ } {} + explicit Reference(CollaborationRef data, StrRange position_ = {}) noexcept + : data{ std::move(data) }, type{ ReferenceType::collaboration }, position{ position_ } {} + + [[nodiscard]] static Reference Parse(std::string_view refStr); + [[nodiscard]] static std::vector ExtractAll(std::string_view text); + + //! Common API + [[nodiscard]] ReferenceType GetType() const noexcept; + [[nodiscard]] bool IsValid() const noexcept; + [[nodiscard]] bool IsEntity() const noexcept; + [[nodiscard]] bool IsCollaboration() const noexcept; + [[nodiscard]] std::string ToString() const; + + //! Entity specific API + [[nodiscard]] std::string_view GetEntity() const; + [[nodiscard]] const Morphology& GetForm() const; + [[nodiscard]] bool TranslateEntity(const StrTranslator& old2New); + void ResolveEntity(const EntityTermContext& context); + + //! Collaboration specific API + [[nodiscard]] int16_t GetOffset() const; + [[nodiscard]] const std::string& GetNominal() const; + void ResolveCollaboration(const Reference* master); +}; + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/RefsManager.h b/ccl/cclLang/include/ccl/lang/RefsManager.h new file mode 100644 index 0000000..cf96db6 --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/RefsManager.h @@ -0,0 +1,84 @@ +#pragma once + +#include "ccl/lang/Reference.h" + +namespace ccl::lang { + +//! References management for a string +/* + * Represents vector of references for a contiguous text + * Vector is ordered by start position. + * Positions do not overlap. + * Positions are separated by at least 1 symbol. + * External iterator functor is used to inject position updates. +*/ +class RefsManager { + std::vector refs{}; + const EntityTermContext* context{ nullptr }; + +public: + RefsManager() noexcept = default; + explicit RefsManager(const EntityTermContext& cntxt) noexcept; + + [[nodiscard]] const auto& get() const noexcept { return refs; } + + void clear() noexcept { + refs.clear(); + } + + void SetContext(const EntityTermContext& cntxt) noexcept; + + //! Resolve references from \p text and calculate resolved positions + // Pre: context != nullptr + std::string Resolve(std::string_view text); + + //! Add reference and update positions for other references + //! // Pre: context != nullptr + const Reference* Insert(Reference newRef, StrPos insWhere); + + //! Update data positions using \p RangeIterator + /* + Note: returns false if position count doesnt match data count + or position length doesnt match data length + */ + template + bool UpdatePositions(RangeIterator nextPos); + + //! Erase references in range or at position + std::optional EraseIn(StrRange range, bool expandRefs = false); + + //! Get data representing given \p range + [[nodiscard]] const Reference* FirstIn(StrRange range) const; + + //! Generate text with references from plain text using data positions for replacements + /* + Pre: + * length of \p normStr should be sufficient to replace all positions + * subRange.start < size(normstr) + */ + [[nodiscard]] std::string OutputRefs(const std::string& normStr) const; + [[nodiscard]] std::string OutputRefs(const std::string& normStr, StrRange subRange) const; + +private: + using RefIter = std::vector::iterator; + void ResolveAll(); + void ResolveIt(RefIter target); + [[nodiscard]] const Reference* FindMaster(RefIter base, int16_t offset) const; + std::string GenerateResolved(std::string_view text); +}; + +template +bool RefsManager::UpdatePositions(RangeIterator nextPos) { + auto refIt = std::begin(refs); + auto position = nextPos(StrRange{ 0, 0 }); + for (; position.has_value(); position = nextPos(*position), ++refIt) { + if (refIt == std::end(refs)) { + return false; + } else { + refIt->position = position.value(); + } + } + return refIt == std::end(refs) && (!position.has_value() || !nextPos(position.value()).has_value()); +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/TextEnvironment.h b/ccl/cclLang/include/ccl/lang/TextEnvironment.h new file mode 100644 index 0000000..f24c0ae --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/TextEnvironment.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ccl/lang/TextProcessor.h" + +#include + +namespace ccl::lang { + +class TextEnvironment final { +private: + std::unique_ptr processor{ std::make_unique() }; + +public: + bool skipResolving{ false }; + +public: + static void SetProcessor(std::unique_ptr newProcessor) noexcept; + [[nodiscard]] static TextProcessor& Processor() noexcept; + [[nodiscard]] static TextEnvironment& Instance() noexcept; +}; + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/include/ccl/lang/TextProcessor.h b/ccl/cclLang/include/ccl/lang/TextProcessor.h new file mode 100644 index 0000000..5ced6b9 --- /dev/null +++ b/ccl/cclLang/include/ccl/lang/TextProcessor.h @@ -0,0 +1,40 @@ +#pragma once + +#include "ccl/lang/Morphology.h" + +#include + +namespace ccl::lang { + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +//! Abstract text processor +class TextProcessor { +public: + virtual ~TextProcessor() noexcept = default; + TextProcessor() noexcept = default; + +protected: + TextProcessor(const TextProcessor&) = default; + TextProcessor& operator=(const TextProcessor&) = default; + TextProcessor(TextProcessor&&) noexcept = default; + TextProcessor& operator=(TextProcessor&&) noexcept = default; + +public: + [[nodiscard]] virtual std::string Inflect(const std::string& target, const Morphology& form) const; + [[nodiscard]] virtual std::string InflectDependant(const std::string& dependant, const std::string& main) const; + [[nodiscard]] virtual bool IsSubstr(const std::string& needle, const std::string& haystack) const; + +private: + [[nodiscard]] static bool BasicSTDMatch(const std::string& needle, const std::string& haystack); + [[nodiscard]] static bool RegexMatch(const std::string& strRegex, const std::string& strHaystack); +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/LexicalTerm.cpp b/ccl/cclLang/src/LexicalTerm.cpp new file mode 100644 index 0000000..9a76daf --- /dev/null +++ b/ccl/cclLang/src/LexicalTerm.cpp @@ -0,0 +1,76 @@ +#include "ccl/lang/LexicalTerm.h" + +#include "ccl/lang/EntityTermContext.hpp" +#include "ccl/lang/TextEnvironment.h" + +namespace ccl::lang { + +void LexicalTerm::SetText(std::string_view ref, const EntityTermContext& cntxt) { + if (ref != text.Raw()) { + text.InitFrom(ref, cntxt); + ClearForms(); + } +} + +void LexicalTerm::TranslateRefs(const StrTranslator& old2New, const EntityTermContext& cntxt) { + text.TranslateRefs(old2New, cntxt); + cachedForms.clear(); +} + +void LexicalTerm::TranslateRaw(const StrTranslator& old2New) { + text.TranslateRaw(old2New); + cachedForms.clear(); +} + +void LexicalTerm::SetForm(const Morphology& form, std::string_view formText) { + manualForms[form] = formText; + cachedForms.erase(form); +} + +bool LexicalTerm::operator==(const LexicalTerm& t2) const noexcept { + return text == t2.text; +} + +void LexicalTerm::UpdateFrom(const EntityTermContext& cntxt) { + text.UpdateFrom(cntxt); + cachedForms.clear(); +} + +bool LexicalTerm::MatchStr(const std::string& str) const { + return TextEnvironment::Processor().IsSubstr(str, GetNominalForm()); +} + +void LexicalTerm::ClearForms() noexcept { + manualForms.clear(); + cachedForms.clear(); +} + +bool LexicalTerm::IsFormManual(const Morphology& form) const { + return manualForms.contains(form); +} + +const std::string& LexicalTerm::GetManualForm(const Morphology& form) const { + return manualForms.at(form); +} + +const std::string& LexicalTerm::GetNominalForm() const { + return GetForm(Morphology{ Grammem::sing, Grammem::nomn }); +} + +const std::unordered_map& LexicalTerm::GetAllManual() const { + return manualForms; +} + +const std::string& LexicalTerm::GetForm(const Morphology& form) const { + if (manualForms.contains(form)) { + return manualForms.at(form); + } else if (cachedForms.contains(form)) { + return cachedForms.at(form); + } else if (std::empty(form)) { + return GetNominalForm(); + } + cachedForms.emplace(form, TextEnvironment::Processor().Inflect(text.Str(), form)); + return cachedForms.at(form); +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/Literals.cpp b/ccl/cclLang/src/Literals.cpp new file mode 100644 index 0000000..7090ace --- /dev/null +++ b/ccl/cclLang/src/Literals.cpp @@ -0,0 +1,13 @@ +#include "ccl/lang/Literals.h" + +namespace ccl::lang { + +Morphology operator""_form(const char* input, size_t /*size*/) { + return Morphology(input); +} + +Reference operator""_ref(const char* input, size_t size) { + return Reference::Parse(std::string_view(input, size)); +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/ManagedText.cpp b/ccl/cclLang/src/ManagedText.cpp new file mode 100644 index 0000000..921294b --- /dev/null +++ b/ccl/cclLang/src/ManagedText.cpp @@ -0,0 +1,58 @@ +#include "ccl/lang/ManagedText.h" + +#include "ccl/lang/RefsManager.h" +#include "ccl/lang/EntityTermContext.hpp" +#include "ccl/lang/TextEnvironment.h" + +namespace ccl::lang { + +bool ManagedText::operator==(const ManagedText& str2) const noexcept { return rawText == str2.rawText; } +bool ManagedText::operator!=(const ManagedText& str2) const noexcept { return rawText != str2.rawText; } +bool ManagedText::empty() const noexcept { return std::empty(rawText); } +const std::string& ManagedText::Str() const noexcept { return std::empty(cache) ? rawText : cache; } +const std::string& ManagedText::Raw() const noexcept { return rawText; } + +void ManagedText::InitFrom(std::string_view ref, const EntityTermContext& cntxt) { + rawText = ref; + UpdateFrom(cntxt); +} + +void ManagedText::SetRaw(std::string_view ref) { + rawText = ref; + cache.clear(); +} + +void ManagedText::TranslateRefs(const StrTranslator& old2New, const EntityTermContext& cntxt) { + TranslateRaw(old2New); + UpdateFrom(cntxt); +} + +void ManagedText::TranslateRaw(const StrTranslator& old2New) { + auto refs = Reference::ExtractAll(rawText); + for (auto ref = rbegin(refs); ref != rend(refs); ++ref) { + if (ref->IsEntity() && ref->TranslateEntity(old2New)) { + const auto start = UTF8Iterator(rawText, ref->position.start).BytePosition(); + const auto oldLength = UTF8Iterator(rawText, ref->position.finish).BytePosition() - start; + rawText.replace(start, oldLength, ref->ToString()); + } + } +} + +void ManagedText::UpdateFrom(const EntityTermContext& cntxt) { + if (!TextEnvironment::Instance().skipResolving) { + cache = lang::RefsManager{ cntxt }.Resolve(rawText); + } +} + +std::unordered_set ManagedText::Referals() const { + const auto refs = Reference::ExtractAll(rawText); + std::unordered_set result{}; + for (const auto& ref : refs) { + if (ref.IsEntity()) { + result.emplace(ref.GetEntity()); + } + } + return result; +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/Morphology.cpp b/ccl/cclLang/src/Morphology.cpp new file mode 100644 index 0000000..19da100 --- /dev/null +++ b/ccl/cclLang/src/Morphology.cpp @@ -0,0 +1,62 @@ +#include "ccl/lang/Morphology.h" + +#include + +#include "ccl/Strings.hpp" + +namespace ccl::lang { + +namespace { + +template +Grammem ExtractSingleIntersection(const TagsContainer& tags, const FilterContainer& filter) { + std::vector extracted_set{}; + std::ranges::set_intersection(tags, filter, std::back_inserter(extracted_set)); + if (size(extracted_set) != 1U) { + return Grammem::invalid; + } + else { + return extracted_set.at(0); + } +} + +} // namespace + +std::string Morphology::ToString() const noexcept { + if (empty()) { + return {}; + } + return std::accumulate(next(begin(tags)), end(tags), std::string{ Grammem2Str(*begin(tags))}, + [](std::string result, Grammem arg) { + result += ","; + result += Grammem2Str(arg); + return result; + } + ); +} + +Morphology::Morphology(std::string_view tagsText) + : Morphology(SplitBySymbol(tagsText, ',')) {} + +Morphology::Morphology(const std::vector& tags_) { + for (const auto tag : tags_) { + const auto gram = Str2Grammem(TrimWhitespace(tag)); + if (gram != Grammem::invalid) { + tags.insert(gram); + } + } +} + +bool Morphology::operator==(const Morphology& rval) const noexcept { return tags == rval.tags; } +bool Morphology::operator!=(const Morphology& rval) const noexcept { return !(*this == rval); } +bool Morphology::Contains(Grammem gram) const noexcept { return tags.contains(gram); } +size_t Morphology::size() const noexcept { return std::size(tags); } +bool Morphology::empty() const noexcept { return std::empty(tags); } +Grammem Morphology::GetPOS() const { return ExtractSingleIntersection(tags, ALL_POS); } +Grammem Morphology::GetCase() const { return ExtractSingleIntersection(tags, ALL_CASES); } +Grammem Morphology::GetNumber() const { return ExtractSingleIntersection(tags, ALL_NUMBERS); } +Grammem Morphology::GetGender() const { return ExtractSingleIntersection(tags, ALL_GENDERS); } +Grammem Morphology::GetTense() const { return ExtractSingleIntersection(tags, ALL_TENSES); } +Grammem Morphology::GetPerson() const { return ExtractSingleIntersection(tags, ALL_PERSONS); } + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/Reference.cpp b/ccl/cclLang/src/Reference.cpp new file mode 100644 index 0000000..9bb0a86 --- /dev/null +++ b/ccl/cclLang/src/Reference.cpp @@ -0,0 +1,214 @@ +#include "ccl/lang/Reference.h" + +// TODO: Use format library for GCC when available (GCC13+) +#if !defined(__GNUC__) && !defined(__clang__) +#include +#endif + +#include "ccl/lang/TextEnvironment.h" +#include "ccl/lang/LexicalTerm.h" + +namespace ccl::lang { + +namespace { + +[[nodiscard]] const std::string& EmptyRefCheck(const std::string& result) { + static const std::string emptyOut{ R"(!Empty reference!)" }; + if (empty(result)) { + return emptyOut; + } else { + return result; + } +} + +[[nodiscard]] std::vector SplitReference(std::string_view ref) { + static constexpr auto prefixLen = 2U; // prefix string: "@{" + static constexpr auto suffixLen = 1U; // suffix string: "}" + if (ref.size() <= prefixLen + suffixLen) { + return {}; + } else { + return SplitBySymbol(ref.substr(prefixLen, ref.length() - prefixLen - suffixLen), '|'); + } +} + +[[nodiscard]] ReferenceType DeduceRefType(const std::vector& tokens) noexcept { + if (size(tokens) < EntityRef::fieldCount || size(tokens) > EntityRef::fieldCount + 2) { + return ReferenceType::invalid; + } + const auto firstToken = tokens.at(0); + if (empty(firstToken)) { + return ReferenceType::invalid; + } + const auto& firstSymbol = firstToken.at(0); + if (isalpha(firstSymbol)) { + return ReferenceType::entity; + } else if (IsInteger(firstToken) && size(tokens) == CollaborationRef::fieldCount) { + return ReferenceType::collaboration; + } + return ReferenceType::invalid; +} + +[[nodiscard]] Morphology ExtractMorpho(const std::vector& tokens) noexcept { + if (size(tokens) == EntityRef::fieldCount) { + return Morphology{ tokens.at(EntityRef::TR_TAGS) }; + } else { + auto tags = tokens; + tags.erase(begin(tags)); + if (std::isdigit(tags.rbegin()->at(0))) { + tags.erase(prev(end(tags))); + } + return Morphology{ tags }; + } +} + +[[nodiscard]] UTF8Iterator ReferenceStart(const std::string_view refStr, const StrPos start) noexcept { + for (auto iter = UTF8Iterator(refStr, start); iter != UTF8End(refStr); ++iter) { + if (*iter == '@') { + if (++iter == UTF8End(refStr) || *iter == '{') { + return iter; + } + } + } + return UTF8End(refStr); +} + +[[nodiscard]] UTF8Iterator ReferenceEnd(const std::string_view refStr, const UTF8Iterator start) noexcept { + auto bracketCount = 0; + for (auto iter = start; iter != UTF8End(refStr); ++iter) { + if (*iter == '{') { + ++bracketCount; + } else if (*iter == '}') { + --bracketCount; + } + if (bracketCount == 0) { + return iter; + } + } + return UTF8End(refStr); +} + +[[nodiscard]] std::optional +NextReference(const std::string_view refStr, const StrPos start = 0) noexcept { + if (const auto refStart = ReferenceStart(refStr, start); refStart == UTF8End(refStr)) { + return std::nullopt; + } else if (const auto refEnd = ReferenceEnd(refStr, refStart); refEnd == UTF8End(refStr)) { + return std::nullopt; + } else { + return StrRange{ refStart.Position() - 1, refEnd.Position() + 1 }; + } +} + +} // namespace + +std::string EntityRef::ToString() const { +#if !defined(__GNUC__) && !defined(__clang__) + return std::format("@{{{}|{}}}", entity, form.ToString()); +#else + return "@{" + entity + '|' + form.ToString() + '}'; +#endif +} + +std::string CollaborationRef::ToString() const { +#if !defined(__GNUC__) && !defined(__clang__) + return std::format("@{{{}|{}}}", offset, nominal); +#else + return "@{" + std::to_string(offset) + '|' + nominal + '}'; +#endif +} + +Reference Reference::Parse(std::string_view refStr) { + const auto tokens = SplitReference(refStr); + const auto type = DeduceRefType(tokens); + switch (type) { + case ReferenceType::entity: { + auto form = ExtractMorpho(tokens); + if (std::empty(form)) { + return {}; + } + return Reference{ EntityRef{ std::string{ tokens.at(EntityRef::TR_ENTITY) }, std::move(form) } }; + } + case ReferenceType::collaboration: { + return Reference{ + CollaborationRef{ std::string{ tokens.at(CollaborationRef::CR_TEXT) }, + static_cast(stoi(std::string{ tokens.at(CollaborationRef::CR_OFFSET) })) } + }; + } + default: + case ReferenceType::invalid: return {}; + } +} + +std::vector Reference::ExtractAll(const std::string_view text) { + std::vector result{}; + for (auto position = NextReference(text); position.has_value(); + position = NextReference(text, position->finish)) { + if (auto ref = Reference::Parse(Substr(text, position.value())); ref.IsValid()) { + ref.position = position.value(); + result.emplace_back(std::move(ref)); + } + } + return result; +} + +ReferenceType Reference::GetType() const noexcept { return type; } +bool Reference::IsValid() const noexcept { return GetType() != ReferenceType::invalid; } +bool Reference::IsEntity() const noexcept { return GetType() == ReferenceType::entity; } +bool Reference::IsCollaboration() const noexcept { return GetType() == ReferenceType::collaboration; } +std::string_view Reference::GetEntity() const { return std::get(data).entity; } +const Morphology& Reference::GetForm() const { return std::get(data).form; } + +bool Reference::TranslateEntity(const StrTranslator& old2New) { + auto& refData = std::get(data); + const auto newID = old2New(refData.entity); + if (!newID.has_value() || newID.value() == refData.entity) { + return false; + } + refData.entity = newID.value(); + return true; +} + +int16_t Reference::GetOffset() const { return std::get(data).offset; } +const std::string& Reference::GetNominal() const { return std::get(data).nominal; } + +std::string Reference::ToString() const { + switch (type) { + case ReferenceType::entity: return std::get(data).ToString(); + case ReferenceType::collaboration: return std::get(data).ToString(); + default: + case ReferenceType::invalid: return ""; + } +} + +void Reference::ResolveCollaboration(const Reference* master) { + const auto& refData = std::get(data); + if (empty(refData.nominal)) { + resolvedText = EmptyRefCheck(refData.nominal); + } else if(master == nullptr) { +#if !defined(__GNUC__) && !defined(__clang__) + resolvedText = std::format("!Invalid offset for {}: '{}'!", refData.nominal, refData.offset); +#else + resolvedText = "!Invalid offset for " + refData.nominal + ": '" + std::to_string(refData.offset) + "'!"; +#endif + } else { + resolvedText = EmptyRefCheck(TextEnvironment::Processor().InflectDependant(refData.nominal, master->resolvedText)); + } +} + +void Reference::ResolveEntity(const EntityTermContext& context) { + auto& refData = std::get(data); + if (empty(refData.entity)) { + resolvedText = EmptyRefCheck(refData.entity); + } else if (const auto* entity = context.At(refData.entity); entity == nullptr) { +#if !defined(__GNUC__) && !defined(__clang__) + resolvedText = std::format("!Cannot find entity: '{}'!", refData.entity); +#else + resolvedText = "!Cannot find entity: '" + refData.entity +"'!"; +#endif + } else if (auto result = entity->GetForm(refData.form); std::empty(result)) { + resolvedText = EmptyRefCheck(entity->Nominal()); + } else { + resolvedText = EmptyRefCheck(result); + } +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/RefsManager.cpp b/ccl/cclLang/src/RefsManager.cpp new file mode 100644 index 0000000..637d9b5 --- /dev/null +++ b/ccl/cclLang/src/RefsManager.cpp @@ -0,0 +1,222 @@ +#include "ccl/lang/RefsManager.h" + +#include "ccl/lang/LexicalTerm.h" + +namespace ccl::lang { + +namespace { + +void ShiftAllAfter(std::vector& refs, std::vector::iterator pos, StrPos shift) { + if (pos != end(refs)) { + for (auto shiftIt = next(pos); shiftIt != end(refs); ++shiftIt) { + shiftIt->position.Shift(shift); + } + } +} + +} // namespace + +const Reference* RefsManager::FirstIn(const StrRange range) const { + for (auto it = begin(refs); it != end(refs); ++it) { + if (range.IsAfter(it->position)) { + continue; + } else if (range.IsBefore(it->position)) { + return nullptr; + } else { + return &*it; + } + } + return nullptr; +} + +RefsManager::RefsManager(const EntityTermContext& cntxt) noexcept : + context{ &cntxt } {} + +void RefsManager::SetContext(const EntityTermContext& cntxt) noexcept { + context = &cntxt; +} + +std::string RefsManager::Resolve(std::string_view text) { + refs = Reference::ExtractAll(text); + ResolveAll(); + return GenerateResolved(text); +} + +void RefsManager::ResolveAll() { + for (auto it = begin(refs); it != end(refs); ++it) { + if (it->IsEntity()) { + it->ResolveEntity(*context); + } + } + for (auto it = begin(refs); it != end(refs); ++it) { + if (it->IsCollaboration()) { + const auto* master = FindMaster(it, it->GetOffset()); + it->ResolveCollaboration(master); + } + } +} + +std::string RefsManager::GenerateResolved(std::string_view text) { + std::string resolvedString{}; + StrPos difLen = 0; + auto current = UTF8Begin(text); + for (auto it = begin(refs); it != end(refs); ++it) { + if (current.Position() != it->position.start) { + resolvedString += text.substr(current.BytePosition(), + UTF8Iterator(text, it->position.start).BytePosition() - current.BytePosition()); + } + current = UTF8Iterator(text, it->position.finish); + const auto resolvedRefText = it->resolvedText; + resolvedString += resolvedRefText; + const auto unresolvedLength = it->position.length(); + const auto resolvedLength = SizeInCodePoints(resolvedRefText); + it->position = StrRange::FromLength(it->position.start + difLen, resolvedLength); + difLen += resolvedLength - unresolvedLength; + } + if (current != UTF8End(text)) { + resolvedString += text.substr(current.BytePosition(), size(text) - current.BytePosition()); + } + return resolvedString; +} + +const Reference* RefsManager::Insert(Reference newRef, const StrPos insWhere) { + assert(context != nullptr); + auto it = std::find_if(begin(refs), end(refs), + [&](const Reference& hold) + { return hold.position.start >= insWhere; }); + if (it != end(refs) && + (it->position.Contains(insWhere) || it->position.finish == insWhere)) { + return nullptr; + } else if (it != begin(refs) && !empty(refs) && + (prev(it)->position.Contains(insWhere) || prev(it)->position.finish == insWhere)) { + return nullptr; + } + + it = refs.emplace(it, std::move(newRef)); + ResolveIt(it); + const auto resultLen = SizeInCodePoints(it->resolvedText); + it->position = StrRange::FromLength(insWhere, resultLen); + ShiftAllAfter(refs, it, resultLen); + return &*it; +} + +std::optional RefsManager::EraseIn(StrRange range, const bool expandRefs) { + bool checkFinish = false; + + auto eraseStart = end(refs); + auto refIt = begin(refs); + + for (; refIt != end(refs); ++refIt) { + const auto& refPosition = refIt->position; + if (refPosition.Meets(range)) { + checkFinish = true; + continue; + } else if (refPosition.IsBefore(range)) { + continue; + } + + if (range.Meets(refPosition)) { + if (checkFinish) { + return std::nullopt; + } else { + break; + } + } else if (refPosition.IsAfter(range)) { + break; + } + + if (refPosition.Contains(range) && expandRefs) { + range = refPosition; + } + + if (range.Contains(refPosition)) { + if (eraseStart != end(refs)) { + continue; + } else { + eraseStart = refIt; + } + } else { + return std::nullopt; + } + } + ShiftAllAfter(refs, refIt, -range.length()); + if (refIt != end(refs)) { + refIt->position.Shift(-range.length()); + } + if (eraseStart != end(refs)) { + refs.erase(eraseStart, refIt); + } + + return range; +} + +std::string RefsManager::OutputRefs(const std::string& normStr) const { + return OutputRefs(normStr, StrRange{ 0, SizeInCodePoints(normStr) }); +} + +std::string RefsManager::OutputRefs(const std::string& normStr, const StrRange subRange) const { + std::string result{}; + auto curPos = subRange.start; + auto finish = subRange.finish; + for (const auto& ref : refs) { + const auto intersection = subRange.Intersect(ref.position); + if (!intersection.has_value() || intersection->length() == 0) { + if (subRange.IsBefore(ref.position)) { + break; + } + } else if (intersection->length() * 2 < ref.position.length()) { + if (ref.position.finish >= finish) { + finish = std::min(finish, ref.position.start); + break; + } else { + curPos = std::max(curPos, ref.position.finish); + } + } else { + if (curPos < ref.position.start) { + result += Substr(normStr, StrRange{ curPos, ref.position.start }); + } + result += ref.ToString(); + curPos = ref.position.finish; + } + } + if (curPos < finish) { + result += Substr(normStr, StrRange{ curPos, finish }); + } + return result; +} + +void RefsManager::ResolveIt(RefIter target) { + if (target->IsEntity()) { + target->ResolveEntity(*context); + } else { + const auto* master = FindMaster(target, target->GetOffset()); + target->ResolveCollaboration(master); + } +} + +const Reference* RefsManager::FindMaster(const RefIter base, const int16_t offset) const { + if (offset == 0) { + return nullptr; + } + auto termCounter = abs(offset); + const auto boundary = offset > 0 ? prev(end(refs)) : begin(refs); + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 26496 ) // Note: false positive const for iterator +#endif + const auto sign = offset > 0 ? 1 : -1; + for (auto it = base; it != boundary; ) { + std::advance(it, sign); + if (it->IsEntity() && (--termCounter == 0)) { + return &*it; + } + } +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + return nullptr; +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/TextEnvironment.cpp b/ccl/cclLang/src/TextEnvironment.cpp new file mode 100644 index 0000000..76842c7 --- /dev/null +++ b/ccl/cclLang/src/TextEnvironment.cpp @@ -0,0 +1,18 @@ +#include "ccl/lang/TextEnvironment.h" + +namespace ccl::lang { + +void TextEnvironment::SetProcessor(std::unique_ptr newProcessor) noexcept { + Instance().processor = std::move(newProcessor); +} + +TextProcessor& TextEnvironment::Processor() noexcept { + return *Instance().processor; +} + +TextEnvironment& TextEnvironment::Instance() noexcept { + static TextEnvironment instance{}; + return instance; +} + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/src/TextProcessor.cpp b/ccl/cclLang/src/TextProcessor.cpp new file mode 100644 index 0000000..6ad1a57 --- /dev/null +++ b/ccl/cclLang/src/TextProcessor.cpp @@ -0,0 +1,55 @@ +#include "ccl/lang/TextProcessor.h" + +#include + +namespace ccl::lang { + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +std::string TextProcessor::Inflect(const std::string& target, const Morphology& /*morpho*/) const { + return target; +} + +std::string TextProcessor::InflectDependant(const std::string& dependant, const std::string& /*main*/) const { + return dependant; +} + +bool TextProcessor::IsSubstr(const std::string& needle, const std::string& haystack) const { + if (needle == haystack) { + return true; + } else if (empty(needle)) { + return true; + } else if (BasicSTDMatch(needle, haystack)) { + return true; + } else { + return RegexMatch(needle, haystack); + } +} + +bool TextProcessor::BasicSTDMatch(const std::string& needle, const std::string& haystack) { + const auto it = std::search( + begin(haystack), end(haystack), + begin(needle), end(needle), + [](char ch1, char ch2) noexcept { return ::toupper(ch1) == ::toupper(ch2); } + ); + return (it != end(haystack)); +} + +bool TextProcessor::RegexMatch(const std::string& strRegex, const std::string& strHaystack) { + try { + const std::regex testRegex(std::data(strRegex), std::size(strRegex)); + return std::sregex_iterator(begin(strHaystack), end(strHaystack), testRegex) != std::sregex_iterator(); + } + catch (const std::regex_error&) { + return false; + } +} + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl::lang \ No newline at end of file diff --git a/ccl/cclLang/test/CMakeLists.txt b/ccl/cclLang/test/CMakeLists.txt new file mode 100644 index 0000000..e883315 --- /dev/null +++ b/ccl/cclLang/test/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.23) + +find_package(GTest REQUIRED) + +add_executable(cclLang_Tests) +target_sources(cclLang_Tests + PRIVATE + unity/cclLangTest.cpp +) +target_include_directories(cclLang_Tests + PRIVATE + ../header + ../import/include + utils +) +target_link_libraries(cclLang_Tests + PRIVATE + cclLang + ccl_CXXwarnings + ccl_CXXoptions + GTest::gtest + GTest::gtest_main +) + +include(GoogleTest) +gtest_discover_tests(cclLang_Tests) \ No newline at end of file diff --git a/ccl/cclLang/test/cclLangTest.vcxproj b/ccl/cclLang/test/cclLangTest.vcxproj new file mode 100644 index 0000000..e01714a --- /dev/null +++ b/ccl/cclLang/test/cclLangTest.vcxproj @@ -0,0 +1,226 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4754356B-DC01-4564-A035-270FFB72F6A0} + Win32Proj + 10.0 + Application + v143 + Unicode + cclLangTest + + + + true + + + + true + + + + true + + + true + + + + + + + + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + + + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + + + build\x86\$(Configuration)\ + build\x86\$(Configuration)\ + false + false + + + false + build\x64\$(Configuration)\ + build\x64\$(Configuration)\ + false + + + + {76B03803-56CC-47C2-A8F0-2241FCAF2898} + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories) + Disabled + true + true + + + true + Console + cclLangd.lib;%(AdditionalDependencies) + false + ..\..\..\output\lib\x86;%(AdditionalLibraryDirectories) + + + + + NotUsing + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Level4 + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories) + Disabled + false + true + true + + + true + Console + cclLangd.lib;%(AdditionalDependencies) + false + ..\..\..\output\lib\x64;%(AdditionalLibraryDirectories) + + + + + NotUsing + + + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + cclLang.lib;%(AdditionalDependencies) + ..\..\..\output\lib\x86;%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration + + + true + + + + + NotUsing + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + ProgramDatabase + true + stdcpplatest + $(IntDir) + $(IntDir)obj\ + $(IntDir) + true + utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories) + true + true + true + + + true + Console + true + true + cclLang.lib;%(AdditionalDependencies) + ..\..\..\output\lib\x64;%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration + false + + + true + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/ccl/cclLang/test/cclLangTest.vcxproj.filters b/ccl/cclLang/test/cclLangTest.vcxproj.filters new file mode 100644 index 0000000..a1cc70e --- /dev/null +++ b/ccl/cclLang/test/cclLangTest.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {ed04b33d-515f-46b0-aad1-54dcbc55a5fd} + + + {e557a0c7-3116-47e0-9713-487c7e6cc101} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + + + utils + + + utils + + + utils + + + utils + + + + + + \ No newline at end of file diff --git a/ccl/cclLang/test/packages.config b/ccl/cclLang/test/packages.config new file mode 100644 index 0000000..be1fa03 --- /dev/null +++ b/ccl/cclLang/test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ccl/cclLang/test/src/testLexicalTerm.cpp b/ccl/cclLang/test/src/testLexicalTerm.cpp new file mode 100644 index 0000000..74c60f2 --- /dev/null +++ b/ccl/cclLang/test/src/testLexicalTerm.cpp @@ -0,0 +1,132 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "RefHelper.hpp" +#include "FakeTextProcessor.hpp" +#include "FakeTermContext.hpp" + +#include "ccl/Substitutes.hpp" +#include "ccl/lang/EntityTermContext.hpp" +#include "ccl/lang/Literals.h" + +using ccl::lang::operator""_form; + +class UTLexcicalTerm : public ::testing::Test { +protected: + FakeContext cntxt{}; + +protected: + using LexicalTerm = ccl::lang::LexicalTerm; + using ManagedText = ccl::lang::ManagedText; + using Morphology = ccl::lang::Morphology; + using TextEnvironment = ccl::lang::TextEnvironment; + + void SetUp() override { + cntxt.Insert("X1", LexicalTerm{ "Test" }); + } + void TearDown() override { + TextEnvironment::SetProcessor(std::make_unique()); + } +}; + +TEST_F(UTLexcicalTerm, DefaultParams) { + const LexicalTerm term{}; + EXPECT_EQ(term, LexicalTerm()); + EXPECT_EQ(term.Text(), ManagedText()); + EXPECT_TRUE(term.MatchStr("")); +} + +TEST_F(UTLexcicalTerm, Access) { + const LexicalTerm term{"raw", "cached"}; + EXPECT_EQ(term.Nominal(), "cached"); + EXPECT_EQ(term.Text().Str(), "cached"); + EXPECT_EQ(term.Text().Raw(), "raw"); +} + +TEST_F(UTLexcicalTerm, SetText) { + LexicalTerm term{}; + term.SetText("generic", cntxt); + EXPECT_EQ(term.Nominal(), "generic"); + + term.SetText("generic " + FakeTextProcessor::x1Ref, cntxt); + EXPECT_EQ(term.Nominal(), "generic Test"); +} + +TEST_F(UTLexcicalTerm, UpdateContext) { + auto term = LexicalTerm{ FakeTextProcessor::x1Ref }; + EXPECT_EQ(FakeTextProcessor::x1Ref, term.Nominal()); + term.UpdateFrom(cntxt); + EXPECT_EQ(term.Nominal(), "Test"); +} + +TEST_F(UTLexcicalTerm, SetForm) { + LexicalTerm term{"test", "test"}; + EXPECT_EQ(term.Nominal(), "test"); + EXPECT_EQ(term.GetForm(Morphology{}), "test"); + + term.SetForm(Morphology{}, "42"); + EXPECT_EQ(term.Nominal(), "test"); + EXPECT_EQ(term.GetForm(Morphology{}), "42"); + + term.SetForm("sing,ablt"_form, "43"); + EXPECT_EQ(term.Nominal(), "test"); + EXPECT_EQ(term.GetForm(Morphology{}), "42"); + EXPECT_EQ(term.GetForm("sing,ablt"_form), "43"); +} + +TEST_F(UTLexcicalTerm, GetForm) { + const auto nominalForm = "sing,nomn"_form; + const auto manualForm = "sing,ablt"_form; + const auto cachedForm1 = "sing,datv"_form; + const auto cachedForm2 = "plur,datv"_form; + LexicalTerm term{ "42", "42" }; + term.SetForm(manualForm, "43"); + EXPECT_EQ(term.GetForm(nominalForm), "42"); + EXPECT_EQ(term.GetForm(manualForm), "43"); + EXPECT_EQ(term.GetForm(cachedForm1), "42"); + EXPECT_EQ(term.GetForm(cachedForm1), "42"); + + term.ClearForms(); + term.SetForm(nominalForm, "44"); + EXPECT_EQ(term.GetForm(cachedForm1), "42"); + EXPECT_EQ(term.GetForm(cachedForm2), "42"); +} + +TEST_F(UTLexcicalTerm, GetNominalForm) { + const auto nominalForm = "sing,nomn"_form; + LexicalTerm term{ "42", "42" }; + term.SetForm(nominalForm, "43"); + EXPECT_EQ(term.GetNominalForm(), "43"); +} + +TEST_F(UTLexcicalTerm, IsManualForm) { + LexicalTerm term{ "test", "test" }; + EXPECT_FALSE(term.IsFormManual(Morphology{})); + + term.SetForm({}, "42"); + EXPECT_TRUE(term.IsFormManual(Morphology{})); + + term.SetForm({}, "test"); + EXPECT_TRUE(term.IsFormManual(Morphology{})); +} + +TEST_F(UTLexcicalTerm, TranslateRefs) { + const auto manualForm = "sing,ablt"_form; + LexicalTerm term{ tccl::EntityRef("X2"), "cache" }; + term.SetForm(manualForm, "man"); + term.TranslateRefs(ccl::CreateTranslator({ { "X2", "X1" } }), cntxt); + EXPECT_EQ("man", term.GetForm(manualForm)); + EXPECT_EQ("Test", term.Nominal()); + EXPECT_EQ(tccl::EntityRef("X1"), term.Text().Raw()); +} + +TEST_F(UTLexcicalTerm, TranslateRaw) { + const auto manualForm = "sing,ablt"_form; + LexicalTerm term{ tccl::EntityRef("X2"), "cache" }; + term.SetForm(manualForm, "man"); + term.TranslateRaw(ccl::CreateTranslator({ { "X2", "X1" } })); + EXPECT_EQ("man", term.GetForm(manualForm)); + EXPECT_EQ("cache", term.Nominal()); + EXPECT_EQ(tccl::EntityRef("X1"), term.Text().Raw()); +} \ No newline at end of file diff --git a/ccl/cclLang/test/src/testManagedText.cpp b/ccl/cclLang/test/src/testManagedText.cpp new file mode 100644 index 0000000..0a6b549 --- /dev/null +++ b/ccl/cclLang/test/src/testManagedText.cpp @@ -0,0 +1,129 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "RefHelper.hpp" +#include "FakeTermContext.hpp" + +#include "ccl/lang/ManagedText.h" +#include "ccl/lang/Reference.h" +#include "ccl/lang/TextEnvironment.h" + +class UTManagedText : public ::testing::Test { +protected: + using ManagedText = ccl::lang::ManagedText; + using LexicalTerm = ccl::lang::LexicalTerm; + +protected: + UTManagedText(); + + FakeContext context{}; +}; + +UTManagedText::UTManagedText() { + context.Insert("X1", LexicalTerm{ "Test" }); +} + +TEST_F(UTManagedText, EmptyCache) { + ManagedText text("123", std::string{}); + EXPECT_EQ(text.Str(), "123"); + EXPECT_EQ(text.Raw(), "123"); +} + +TEST_F(UTManagedText, Comparison) { + ManagedText t1{}; + ManagedText t2{ "@test", "1test" }; + ManagedText t3{ "@test", "2test" }; + ManagedText t4{ "@@test", "1test" }; + ManagedText t5{ "@@test" }; + EXPECT_NE(t1, t2); + EXPECT_EQ(t2, t3); + EXPECT_NE(t2, t4); + EXPECT_NE(t3, t4); + EXPECT_EQ(t4, t5); +} + +TEST_F(UTManagedText, Str) { + std::string text{ "test" }; + auto modified = text + "123"; + EXPECT_EQ(ManagedText(text).Str(), text); + EXPECT_EQ(ManagedText(text, modified).Str(), modified); + EXPECT_EQ(ManagedText(modified, text).Str(), text); +} + +TEST_F(UTManagedText, SetRaw) { + ManagedText text{ "42", "43" }; + text.SetRaw("44"); + EXPECT_EQ(text.Raw(), "44"); + EXPECT_EQ(text.Str(), "44"); +} + +TEST_F(UTManagedText, UpdateFrom) { + ManagedText text{ tccl::EntityRef("X1"), "cache" }; + EXPECT_EQ(text.Str(), "cache"); + text.UpdateFrom(context); + EXPECT_EQ(text.Str(), "Test"); +} + +TEST_F(UTManagedText, UpdateFromSkipResolution) { + ManagedText text{ tccl::EntityRef("X1"), "cache" }; + EXPECT_EQ(text.Str(), "cache"); + ccl::lang::TextEnvironment::Instance().skipResolving = true; + text.UpdateFrom(context); + ccl::lang::TextEnvironment::Instance().skipResolving = false; + EXPECT_EQ(text.Str(), "cache"); +} + +TEST_F(UTManagedText, TranslateRaw) { + ManagedText text{ tccl::EntityRef("X2"), "cache" }; + text.TranslateRaw(ccl::CreateTranslator({ {"X2", "X1"} })); + EXPECT_EQ(text.Raw(), tccl::EntityRef("X1")); + EXPECT_EQ(text.Str(), "cache"); +} + +TEST_F(UTManagedText, Referals) { + const ManagedText input{ tccl::EntityRef("X1") }; + const std::unordered_set result{ "X1" }; + EXPECT_EQ(input.Referals(), result); +} + +TEST_F(UTManagedText, ReferalsInvalid) { + EXPECT_EQ(ssize(ManagedText("X1").Referals()), 0); + EXPECT_EQ(ssize(ManagedText("@{X1}").Referals()), 0); +} + +TEST_F(UTManagedText, ReferalsMultiple) { + const ManagedText text{ "@{X2|nomn,sing} text @{abc|nomn,sing} X4 " + "@{-1|testing} @{X1|nomn,sing} @{X2,datv,sing}" }; + EXPECT_EQ(text.Referals(), std::unordered_set({ "X2", "abc", "X1" })); +} + +TEST_F(UTManagedText, ReferalsRepeat) { + const ManagedText text{ tccl::EntityRef("X1") + " " + tccl::EntityRef("X1") }; + EXPECT_EQ(ssize(text.Referals()), 1); +} + +TEST_F(UTManagedText, TranslateRefs) { + { + ManagedText text{ tccl::EntityRef("X2"), "cache" }; + text.TranslateRefs(ccl::CreateTranslator({ {"X2", "X1" } }), context); + EXPECT_EQ(text.Raw(), tccl::EntityRef("X1")); + EXPECT_EQ(text.Str(), "Test"); + } + { + ManagedText text{ tccl::EntityRef("X1") + " " + tccl::EntityRef("X2") }; + text.TranslateRefs(ccl::CreateTranslator({ { "X1", "X11" } }), context); + EXPECT_EQ(text.Raw(), tccl::EntityRef("X11") + " " + tccl::EntityRef("X2")); + } + { + ManagedText text{ tccl::EntityRef("X11") + " " + tccl::EntityRef("X2") }; + text.TranslateRefs(ccl::CreateTranslator({ { "X11", "X1" } }), context); + EXPECT_EQ(text.Raw(), tccl::EntityRef("X1") + " " + tccl::EntityRef("X2")); + } + { + ManagedText text{ tccl::EntityRef("X11") + " \xE2\x84\xAC " + tccl::EntityRef("X21") + " \xE2\x84\xAC " + tccl::EntityRef("X3") }; + auto translator = ccl::CreateTranslator({ { "X11", "X1" }, { "X21", "X2" }, { "X3", "X4" } }); + text.TranslateRefs(translator, context); + EXPECT_EQ(text.Raw(), tccl::EntityRef("X1") + " \xE2\x84\xAC " + tccl::EntityRef("X2") + " \xE2\x84\xAC " + tccl::EntityRef("X4")); + } +} \ No newline at end of file diff --git a/ccl/cclLang/test/src/testMorphology.cpp b/ccl/cclLang/test/src/testMorphology.cpp new file mode 100644 index 0000000..7b19802 --- /dev/null +++ b/ccl/cclLang/test/src/testMorphology.cpp @@ -0,0 +1,107 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" +#include "ccl/lang/Morphology.h" +#include "ccl/lang/Literals.h" + +class UTMorphology : public ::testing::Test { +protected: + using Grammem = ccl::lang::Grammem; + using Morphology = ccl::lang::Morphology; +}; + +TEST_F(UTMorphology, Grammemes) { + EXPECT_EQ(ccl::lang::Str2Grammem(""), Grammem::invalid); + EXPECT_EQ(ccl::lang::Str2Grammem("invalid"), Grammem::invalid); + EXPECT_EQ(ccl::lang::Str2Grammem("PLUR"), Grammem::invalid); + + EXPECT_EQ(ccl::lang::Str2Grammem("plur"), Grammem::plur); + EXPECT_EQ(ccl::lang::Str2Grammem("NOUN"), Grammem::NOUN); + + EXPECT_EQ(ccl::lang::Grammem2Str(Grammem::invalid), "UNKN"); + EXPECT_EQ(ccl::lang::Grammem2Str(Grammem::sing), "sing"); + EXPECT_EQ(ccl::lang::Grammem2Str(Grammem::datv), "datv"); +} + +TEST_F(UTMorphology, Construction) { + using ccl::lang::operator""_form; + + EXPECT_EQ(Morphology{}.ToString(), ""); + EXPECT_EQ(ssize(Morphology{}.tags), 0); + + const Morphology morpho{ Grammem::sing, Grammem::datv }; + EXPECT_EQ(Morphology(morpho.ToString()), morpho); + + EXPECT_EQ(Morphology("sing,datv"), morpho); + EXPECT_EQ(Morphology(" sing , datv "), morpho); + EXPECT_EQ(Morphology("datv,sing"), morpho); + EXPECT_EQ(Morphology("datv,sing,invalid_tag"), morpho); + EXPECT_EQ(Morphology("datv, sing, invalid_tag"), morpho); + + EXPECT_EQ(""_form, Morphology{}); + EXPECT_EQ("datv, sing, invalid_tag"_form, morpho); +} + +TEST_F(UTMorphology, Comparison) { + EXPECT_EQ(Morphology(""), Morphology("")); + EXPECT_EQ(Morphology(" "), Morphology("")); + EXPECT_EQ(Morphology("sing,datv"), Morphology("datv,sing")); + EXPECT_EQ(Morphology("sing,datv"), Morphology("datv,sing")); + EXPECT_EQ(Morphology("sing"), Morphology("sing")); + EXPECT_NE(Morphology("sing,datv"), Morphology("sing")); +} + +TEST_F(UTMorphology, GrammemAccess) { + const Morphology morpho0{}; + EXPECT_EQ(morpho0.GetPOS(), Grammem::invalid); + EXPECT_EQ(morpho0.GetCase(), Grammem::invalid); + EXPECT_EQ(morpho0.GetNumber(), Grammem::invalid); + EXPECT_EQ(morpho0.GetGender(), Grammem::invalid); + EXPECT_EQ(morpho0.GetPerson(), Grammem::invalid); + EXPECT_EQ(morpho0.GetTense(), Grammem::invalid); + + const Morphology morpho1{ Grammem::datv, Grammem::sing }; + EXPECT_EQ(morpho1.GetPOS(), Grammem::invalid); + EXPECT_EQ(morpho1.GetCase(), Grammem::datv); + EXPECT_EQ(morpho1.GetNumber(), Grammem::sing); + EXPECT_EQ(morpho1.GetGender(), Grammem::invalid); + EXPECT_EQ(morpho1.GetPerson(), Grammem::invalid); + EXPECT_EQ(morpho1.GetTense(), Grammem::invalid); + + const Morphology morpho2{ Grammem::NOUN, Grammem::femn, Grammem::sing, Grammem::datv }; + EXPECT_EQ(morpho2.GetPOS(), Grammem::NOUN); + EXPECT_EQ(morpho2.GetCase(), Grammem::datv); + EXPECT_EQ(morpho2.GetNumber(), Grammem::sing); + EXPECT_EQ(morpho2.GetGender(), Grammem::femn); + EXPECT_EQ(morpho2.GetPerson(), Grammem::invalid); + EXPECT_EQ(morpho2.GetTense(), Grammem::invalid); + + const Morphology morpho3{ Grammem::VERB, Grammem::sing, Grammem::per1, Grammem::pres }; + EXPECT_EQ(morpho3.GetPOS(), Grammem::VERB); + EXPECT_EQ(morpho3.GetCase(), Grammem::invalid); + EXPECT_EQ(morpho3.GetNumber(), Grammem::sing); + EXPECT_EQ(morpho3.GetGender(), Grammem::invalid); + EXPECT_EQ(morpho3.GetPerson(), Grammem::per1); + EXPECT_EQ(morpho3.GetTense(), Grammem::pres); +} + +TEST_F(UTMorphology, ContainerAPI) { + EXPECT_EQ(Morphology("").size(), 0U); + EXPECT_EQ(std::size(Morphology("")), 0U); + EXPECT_EQ(std::size(Morphology("datv,sing")), 2U); + + EXPECT_TRUE(Morphology("").empty()); + EXPECT_TRUE(std::empty(Morphology(""))); + EXPECT_FALSE(std::empty(Morphology("NOUN"))); + + EXPECT_FALSE(Morphology("").Contains(Grammem::sing)); + EXPECT_FALSE(Morphology("NOUN,datv").Contains(Grammem::sing)); + EXPECT_TRUE(Morphology("sing,datv").Contains(Grammem::sing)); +} + +TEST_F(UTMorphology, ToString) { + EXPECT_EQ(Morphology("").ToString(), ""); + EXPECT_EQ(Morphology(" datv ").ToString(), "datv"); + const auto tags = Morphology("sing, datv").ToString(); + EXPECT_TRUE(tags == "sing,datv" || tags == "datv,sing"); +} \ No newline at end of file diff --git a/ccl/cclLang/test/src/testReference.cpp b/ccl/cclLang/test/src/testReference.cpp new file mode 100644 index 0000000..6607d89 --- /dev/null +++ b/ccl/cclLang/test/src/testReference.cpp @@ -0,0 +1,278 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "FakeTermContext.hpp" +#include "MockTextProcessor.hpp" +#include "RefHelper.hpp" + +#include "ccl/lang/TextEnvironment.h" +#include "ccl/lang/Reference.h" +#include "ccl/lang/Literals.h" + +using ccl::lang::operator""_form; +using ccl::lang::operator""_ref; + +class UTReference : public ::testing::Test { +protected: + using ReferenceType = ccl::lang::ReferenceType; + using Reference = ccl::lang::Reference; + using EntityRef = ccl::lang::EntityRef; + using CollaborationRef = ccl::lang::CollaborationRef; + using StrRange = ccl::StrRange; + using TextEnvironment = ccl::lang::TextEnvironment; + using TextProcessor = ccl::lang::TextProcessor; + +protected: + static inline const std::string sampleCompanionRef { "@{-1|\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439}" }; + static inline const std::string sampleRef { "\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439" }; + static inline const std::string complexRefStr + { "42 @{X1|nomn,sing} 43 @{-1|basic} 44 @{X1|nomn,sing} 45" }; + static constexpr auto sampleOffset = -1; + static inline const Reference x1ref{ EntityRef{ "X1", "sing,nomn"_form } }; +}; + +TEST_F(UTReference, Construction) { + { + const EntityRef term{ "X1", "sing,nomn"_form }; + const Reference ref{ term, StrRange(1, 4) }; + EXPECT_EQ(ref.position, StrRange(1, 4)); + EXPECT_EQ(ref.resolvedText, ""); + EXPECT_EQ(ref.GetType(), ReferenceType::entity); + EXPECT_EQ(ref.GetEntity(), term.entity); + EXPECT_EQ(ref.GetForm(), term.form); + } + { + const CollaborationRef collab{ "test", 4 }; + const Reference ref{ collab, StrRange(2, 5) }; + EXPECT_EQ(ref.position, StrRange(2, 5)); + EXPECT_EQ(ref.resolvedText, ""); + EXPECT_EQ(ref.GetType(), ReferenceType::collaboration); + EXPECT_EQ(ref.GetOffset(), collab.offset); + EXPECT_EQ(ref.GetNominal(), collab.nominal); + } +} + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 4834 ) // ignore not using return value +#endif + +TEST_F(UTReference, ReferenceID) { + { + const Reference ref{ EntityRef{ "X1", "sing,nomn"_form } }; + ASSERT_EQ(ref.GetType(), ReferenceType::entity); + EXPECT_TRUE(ref.IsEntity()); + EXPECT_FALSE(ref.IsCollaboration()); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); + } + { + const Reference ref{ CollaborationRef{ "text", 1337 }}; + ASSERT_EQ(ref.GetType(), ReferenceType::collaboration); + EXPECT_FALSE(ref.IsEntity()); + EXPECT_TRUE(ref.IsCollaboration()); + EXPECT_EQ(ref.GetOffset(), 1337); + EXPECT_EQ(ref.GetNominal(), "text"); + } +} + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +TEST_F(UTReference, ToString) { + { + const EntityRef term{ "X1", "sing,nomn"_form }; + EXPECT_EQ(term.ToString(), tccl::EntityRef("X1")); + const Reference ref{ term }; + EXPECT_EQ(ref.ToString(), term.ToString()); + } + { + const CollaborationRef collab{ sampleRef, sampleOffset }; + EXPECT_EQ(collab.ToString(), sampleCompanionRef); + const Reference ref{ collab }; + EXPECT_EQ(ref.ToString(), collab.ToString()); + } +} + +TEST_F(UTReference, ParseErrors) { + EXPECT_FALSE(Reference::Parse("").IsValid()); + EXPECT_FALSE(Reference::Parse("@{}").IsValid()); + EXPECT_FALSE(Reference::Parse("@{ }").IsValid()); + EXPECT_FALSE(Reference::Parse("@{|}").IsValid()); + EXPECT_FALSE(Reference::Parse("@{ | }").IsValid()); + EXPECT_FALSE(Reference::Parse("@{ || }").IsValid()); + EXPECT_FALSE(Reference::Parse("@{-1a|text}").IsValid()); + EXPECT_FALSE(Reference::Parse("invalid").IsValid()); + EXPECT_FALSE(Reference::Parse(tccl::EntityRef("X1") + " " + tccl::EntityRef("X2")).IsValid()); +} + +TEST_F(UTReference, ParseEntity) { + auto ref = Reference::Parse(tccl::EntityRef("X1")); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.IsEntity()); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); +} + +TEST_F(UTReference, ParseEntityLegacy) { + const auto form = "sing,nomn"_form; + { + auto ref = Reference::Parse("@{X1|nomn|sing|0}"); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.IsEntity()); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); + } + { + auto ref = Reference::Parse("@{X1|nomn|sing}"); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.IsEntity()); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); + } +} + +TEST_F(UTReference, ParseCollaboration) { + auto ref = Reference::Parse(sampleCompanionRef); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.IsCollaboration()); + EXPECT_EQ(ref.GetOffset(), sampleOffset); + EXPECT_EQ(ref.GetNominal(), sampleRef); +} + +TEST_F(UTReference, ParseReferences) { + const auto parsed = Reference::ExtractAll(complexRefStr); + ASSERT_EQ(3u, std::size(parsed)); + { + EXPECT_EQ(parsed.at(0).position, StrRange(3, 18)); + ASSERT_TRUE(parsed.at(0).IsEntity()); + const auto& ref = parsed.at(0); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); + } + { + EXPECT_EQ(parsed.at(1).position, StrRange(22, 33)); + ASSERT_TRUE(parsed.at(1).IsCollaboration()); + const auto& ref = parsed.at(1); + EXPECT_EQ(ref.GetNominal(), "basic"); + EXPECT_EQ(ref.GetOffset(), -1); + } + { + EXPECT_EQ(parsed.at(2).position, StrRange(37, 52)); + ASSERT_TRUE(parsed.at(2).IsEntity()); + const auto& ref = parsed.at(2); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "sing,nomn"_form); + } +} + +TEST_F(UTReference, ReferenceLiteral) { + const auto ref = "@{X1|nomn,plur}"_ref; + ASSERT_TRUE(ref.IsEntity()); + EXPECT_EQ(ref.GetEntity(), "X1"); + EXPECT_EQ(ref.GetForm(), "nomn,plur"_form); +} + +TEST_F(UTReference, TranslateEntity) { + auto ref = x1ref; + EXPECT_FALSE(ref.TranslateEntity(ccl::CreateTranslator({ { "X42", "X43" } }))); + EXPECT_TRUE(ref.TranslateEntity(ccl::CreateTranslator({ { "X1", "X2" }, { "X2", "X3" } }))); + EXPECT_EQ(ref.GetEntity(), "X2"); +} + +TEST_F(UTReference, ResolveEntity) { + TextEnvironment::SetProcessor(std::make_unique()); + auto& processor = static_cast(TextEnvironment::Processor()); + FakeContext context{}; + + auto emptyRef = Reference{ EntityRef{"", ""_form} }; + emptyRef.ResolveEntity(context); + EXPECT_EQ(emptyRef.resolvedText, "!Empty reference!"); + EXPECT_EQ(size(processor.log), 0U); + + auto ref = x1ref; + ref.ResolveEntity(context); + EXPECT_EQ(ref.resolvedText, "!Cannot find entity: 'X1'!"); + EXPECT_EQ(size(processor.log), 0U); + + context.Insert("X1", ccl::lang::LexicalTerm{ "Test" }); + ref.ResolveEntity(context); + EXPECT_EQ(ref.resolvedText, "Test"); + ASSERT_EQ(size(processor.log), 1U); + EXPECT_EQ(processor.log.at(0).type, tccl::MockTextProcessor::CallType::INFLECT); + EXPECT_EQ(processor.log.at(0).targetText, "Test"); + EXPECT_EQ(processor.log.at(0).form, x1ref.GetForm()); + processor.ClearAll(); + context.Clear(); + + context.Insert("X1", ccl::lang::LexicalTerm{ "" }); + ref.resolvedText.clear(); + ref.ResolveEntity(context); + EXPECT_EQ(ref.resolvedText, "!Empty reference!"); + ASSERT_EQ(size(processor.log), 1U); + EXPECT_EQ(processor.log.at(0).type, tccl::MockTextProcessor::CallType::INFLECT); + EXPECT_EQ(processor.log.at(0).targetText, ""); + EXPECT_EQ(processor.log.at(0).form, x1ref.GetForm()); + + TextEnvironment::SetProcessor(std::make_unique()); +} + +TEST_F(UTReference, ResolveCollaborationEmpty) { + TextEnvironment::SetProcessor(std::make_unique()); + auto& processor = static_cast(TextEnvironment::Processor()); + + auto emptyRef = Reference{ CollaborationRef{ "", 1 } }; + emptyRef.ResolveCollaboration(nullptr); + EXPECT_EQ(emptyRef.resolvedText, "!Empty reference!"); + EXPECT_EQ(size(processor.log), 0U); + + auto master = Reference{ x1ref }; + master.resolvedText = ""; + emptyRef.resolvedText = ""; + emptyRef.ResolveCollaboration(&master); + EXPECT_EQ(emptyRef.resolvedText, "!Empty reference!"); + EXPECT_EQ(size(processor.log), 0U); + + master.resolvedText = "test"; + emptyRef.resolvedText = ""; + emptyRef.ResolveCollaboration(&master); + EXPECT_EQ(emptyRef.resolvedText, "!Empty reference!"); + EXPECT_EQ(size(processor.log), 0U); + + TextEnvironment::SetProcessor(std::make_unique()); +} + +TEST_F(UTReference, ResolveCollaborationValid) { + TextEnvironment::SetProcessor(std::make_unique()); + auto& processor = static_cast(TextEnvironment::Processor()); + + auto collabRef = Reference{ CollaborationRef{ "companion", 1 } }; + collabRef.ResolveCollaboration(nullptr); + EXPECT_EQ(collabRef.resolvedText, "!Invalid offset for companion: '1'!"); + EXPECT_EQ(size(processor.log), 0U); + + auto master = Reference{ x1ref }; + master.resolvedText = ""; + collabRef.resolvedText = ""; + collabRef.ResolveCollaboration(&master); + EXPECT_EQ(collabRef.resolvedText, "companion"); + ASSERT_EQ(size(processor.log), 1U); + EXPECT_EQ(processor.log.at(0).type, tccl::MockTextProcessor::CallType::DEPENDANT); + EXPECT_EQ(processor.log.at(0).targetText, "companion"); + EXPECT_EQ(processor.log.at(0).mainText, ""); + processor.ClearAll(); + + master.resolvedText = "test"; + collabRef.resolvedText = ""; + processor.AddCollaboration(collabRef.GetNominal(), master.resolvedText, "companion_inflected"); + collabRef.ResolveCollaboration(&master); + EXPECT_EQ(collabRef.resolvedText, "companion_inflected"); + ASSERT_EQ(size(processor.log), 1U); + EXPECT_EQ(processor.log.at(0).type, tccl::MockTextProcessor::CallType::DEPENDANT); + EXPECT_EQ(processor.log.at(0).targetText, "companion"); + EXPECT_EQ(processor.log.at(0).mainText, "test"); + + TextEnvironment::SetProcessor(std::make_unique()); +} \ No newline at end of file diff --git a/ccl/cclLang/test/src/testRefsManager.cpp b/ccl/cclLang/test/src/testRefsManager.cpp new file mode 100644 index 0000000..c388020 --- /dev/null +++ b/ccl/cclLang/test/src/testRefsManager.cpp @@ -0,0 +1,304 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "MockTextProcessor.hpp" +#include "FakeTermContext.hpp" +#include "RefHelper.hpp" + +#include "ccl/lang/TextEnvironment.h" +#include "ccl/lang/RefsManager.h" +#include "ccl/lang/Literals.h" + +using ccl::lang::operator""_form; +using ccl::lang::operator""_ref; + +struct FakeUpdater { + using StrRange = ccl::StrRange; + std::vector ranges; + + FakeUpdater(std::vector ranges) + : ranges{ std::move(ranges) } {} + + std::optional operator()(const StrRange& prev) { + if (prev == StrRange{ 0, 0 }) { + if (empty(ranges)) { + return std::nullopt; + } else { + return *begin(ranges); + } + } + if (auto it = std::find(begin(ranges), end(ranges), prev); + it == end(ranges)) { + return std::nullopt; + } else if (++it; it == end(ranges)) { + return std::nullopt; + } else { + return *it; + } + } +}; + +class UTRefsManager : public ::testing::Test { +protected: + using RefsManager = ccl::lang::RefsManager; + using Reference = ccl::lang::Reference; + using Morphology = ccl::lang::Morphology; + using LexicalTerm = ccl::lang::LexicalTerm; + using StrRange = ccl::StrRange; + using TextEnvironment = ccl::lang::TextEnvironment; + using TextProcessor = ccl::lang::TextProcessor; + + FakeContext context{}; + RefsManager refs{}; + +protected: + UTRefsManager(); + + static inline const std::string basicRefStr{"@{X1|sing,nomn}"}; + static inline const std::string complexRefStr + {"42 @{X1|sing,nomn} 43 @{-1|basic} 44 @{X1|sing,nomn} 45"}; + + // refStr: 42 @{X1|sing,nomn} 43 @{-1|basic} 44 @{X1|sing,nomn} 45 + // normStr: 42 Test 43 basic 44 Test 45 + // ---------0000000000111111111122222222 + // ---------0123456789012345678901234567 +}; + +UTRefsManager::UTRefsManager() { + context.Insert("X1", LexicalTerm{ "Test" }); + context.Insert("X2", LexicalTerm{ "Test2" }); + refs.SetContext(context); +} + +TEST_F(UTRefsManager, Constructor) { + const auto emptyMan = RefsManager{}; + EXPECT_TRUE(empty(emptyMan.get())); + const auto manager = RefsManager{ context }; + EXPECT_TRUE(empty(emptyMan.get())); +} + +TEST_F(UTRefsManager, Clear) { + refs.clear(); + EXPECT_EQ(size(refs.get()), 0U); + + refs.SetContext(context); + EXPECT_EQ(size(refs.get()), 0U); + + refs.Resolve(basicRefStr); + EXPECT_EQ(size(refs.get()), 1U); + refs.clear(); + EXPECT_EQ(size(refs.get()), 0U); +} + +TEST_F(UTRefsManager, ResolveValid) { + EXPECT_EQ(refs.Resolve(""), ""); + EXPECT_EQ(std::size(refs.get()), 0U); + + EXPECT_EQ(refs.Resolve("sample text"), "sample text"); + EXPECT_EQ(std::size(refs.get()), 0U); + + EXPECT_EQ(refs.Resolve(basicRefStr), "Test"); + ASSERT_EQ(size(refs.get()), 1U); + EXPECT_EQ(begin(refs.get())->position, StrRange(0, 4)); + + EXPECT_EQ(refs.Resolve(complexRefStr), "42 Test 43 basic 44 Test 45"); + ASSERT_EQ(size(refs.get()), 3U); + EXPECT_EQ(refs.get().at(0).position, StrRange(3, 7)); + EXPECT_EQ(refs.get().at(1).position, StrRange(11, 16)); + EXPECT_EQ(refs.get().at(2).position, StrRange(20, 24)); +} + +TEST_F(UTRefsManager, ResolveCompanionOffsets) { + TextEnvironment::SetProcessor(std::make_unique()); + auto& processor = static_cast(TextEnvironment::Processor()); + + EXPECT_EQ(refs.Resolve("@{-1|basic}"), "!Invalid offset for basic: '-1'!"); + EXPECT_EQ(refs.Resolve("@{-1|basic} @{X1|sing,nomn}"), "!Invalid offset for basic: '-1'! Test"); + EXPECT_EQ(refs.Resolve("@{X1|sing,nomn} @{-1|basic}"), "Test basic"); + EXPECT_EQ(refs.Resolve("@{1|basic} @{X1|sing,nomn}"), "basic Test"); + EXPECT_EQ(refs.Resolve("@{1|basic1} @{1|basic1} @{X1|sing,nomn}"), "basic1 basic1 Test"); + EXPECT_EQ(refs.Resolve("@{2|basic1} @{1|basic1} @{X1|sing,nomn}"), "!Invalid offset for basic1: '2'! basic1 Test"); + processor.AddCollaboration("basic", "Test", "basic_inflected"); + EXPECT_EQ(refs.Resolve("@{1|basic} @{X1|sing,nomn}"), "basic_inflected Test"); + + TextEnvironment::SetProcessor(std::make_unique()); +} + +TEST_F(UTRefsManager, Insert) { + const auto newRef = "@{X2|sing,nomn}"_ref; + refs.Resolve(""); + EXPECT_EQ(refs.Insert(newRef, 0)->resolvedText, "Test2"); + ASSERT_EQ(size(refs.get()), 1U); + EXPECT_EQ(begin(refs.get())->position, StrRange(0, 5)); + + refs.Resolve(complexRefStr); + EXPECT_TRUE(refs.Insert(newRef, 3) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 4) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 6) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 7) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 20) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 21) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 23) == nullptr); + EXPECT_TRUE(refs.Insert(newRef, 24) == nullptr); + + refs.Resolve(complexRefStr); + EXPECT_FALSE(refs.Insert(newRef, 2) == nullptr); + + refs.Resolve(complexRefStr); + EXPECT_FALSE(refs.Insert(newRef, 19) == nullptr); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.Insert(newRef, 8)->resolvedText, "Test2"); + ASSERT_EQ(size(refs.get()), 4U); + EXPECT_EQ(refs.get().at(0).position, StrRange(3, 7)); + EXPECT_EQ(refs.get().at(1).position, StrRange(8, 13)); + EXPECT_EQ(refs.get().at(2).position, StrRange(16, 21)); + EXPECT_EQ(refs.get().at(3).position, StrRange(25, 29)); +} + +TEST_F(UTRefsManager, EraseRefsRange) { + EXPECT_TRUE(refs.EraseIn(StrRange{ 0, 0 }).has_value()); + EXPECT_TRUE(refs.EraseIn(StrRange{ 0, 42 }).has_value()); + + refs.Resolve(complexRefStr); + EXPECT_FALSE(refs.EraseIn(StrRange{ 0, 4 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 0, 5 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 0, 6 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 3, 6 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 6, 7 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 4, 5 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 5, 5 }).has_value()); + EXPECT_FALSE(refs.EraseIn(StrRange{ 7, 11 }).has_value()); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 42, 42 }).value(), StrRange(42, 42)); + EXPECT_EQ(refs.EraseIn(StrRange{ 0, 27 }).value(), StrRange(0, 27)); + EXPECT_EQ(std::size(refs.get()), 0U); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 0, 3 }).value(), StrRange(0, 3)); + ASSERT_EQ(std::size(refs.get()), 3U); + EXPECT_EQ(refs.get().at(0).position, StrRange(0, 4)); + EXPECT_EQ(refs.get().at(1).position, StrRange(8, 13)); + EXPECT_EQ(refs.get().at(2).position, StrRange(17, 21)); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 0, 7 }).value(), StrRange(0, 7)); + ASSERT_EQ(std::size(refs.get()), 2U); + EXPECT_EQ(refs.get().at(0).position, StrRange(4, 9)); + EXPECT_EQ(refs.get().at(1).position, StrRange(13, 17)); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 20, 24 }).value(), StrRange(20, 24)); + ASSERT_EQ(size(refs.get()), 2U); + EXPECT_EQ(refs.get().at(0).position, StrRange(3, 7)); + EXPECT_EQ(refs.get().at(1).position, StrRange(11, 16)); +} + +TEST_F(UTRefsManager, EraseRefsExpand) { + EXPECT_TRUE(refs.EraseIn(StrRange{ 0, 1 }, true).has_value()); + + refs.Resolve(complexRefStr); + refs.EraseIn((StrRange{ 7, 10 })); + EXPECT_FALSE(refs.EraseIn(StrRange{ 7, 8 }, true).has_value()); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 2, 3 }, true).value(), StrRange(2, 3)); + ASSERT_EQ(size(refs.get()), 3U); + EXPECT_EQ(refs.get().at(0).position, StrRange(2, 6)); + EXPECT_EQ(refs.get().at(1).position, StrRange(10, 15)); + EXPECT_EQ(refs.get().at(2).position, StrRange(19, 23)); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 3, 4 }, true).value(), StrRange(3, 7)); + ASSERT_EQ(size(refs.get()), 2U); + EXPECT_EQ(refs.get().at(0).position, StrRange(7, 12)); + EXPECT_EQ(refs.get().at(1).position, StrRange(16, 20)); + + refs.Resolve(complexRefStr); + EXPECT_EQ(refs.EraseIn(StrRange{ 6, 7 }, true).value(), StrRange(3, 7)); + ASSERT_EQ(size(refs.get()), 2U); +} + +TEST_F(UTRefsManager, FirstRef) { + EXPECT_TRUE(refs.FirstIn(StrRange{ 0, 0 }) == nullptr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 0, 42 }) == nullptr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 42, 42 }) == nullptr); + + refs.Resolve(complexRefStr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 0, 0 }) == nullptr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 0, 1 }) == nullptr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 27, 27 }) == nullptr); + EXPECT_TRUE(refs.FirstIn(StrRange{ 28, 42 }) == nullptr); + + EXPECT_EQ(refs.FirstIn(StrRange{ 0, 3 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 3, 3 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 3, 6 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 3, 7 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 0, 7 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 6, 12 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 0, 12 }), &refs.get()[0]); + EXPECT_EQ(refs.FirstIn(StrRange{ 12, 12 }), &refs.get()[1]); +} + +TEST_F(UTRefsManager, UpdatePositions) { + EXPECT_TRUE(refs.UpdatePositions(FakeUpdater{ {} })); + EXPECT_FALSE(refs.UpdatePositions(FakeUpdater{ { StrRange{ 0, 1 } } })); + + refs.Resolve(complexRefStr); + EXPECT_FALSE(refs.UpdatePositions(FakeUpdater{ {} })); + EXPECT_FALSE(refs.UpdatePositions(FakeUpdater{ { StrRange{ 0, 1 }, StrRange{ 2, 3 } } })); + EXPECT_FALSE(refs.UpdatePositions(FakeUpdater{ + { StrRange{ 0, 1 }, StrRange{ 2, 3 }, StrRange{ 4, 5 }, StrRange{ 6, 7 } } })); + + refs.Resolve(complexRefStr); + EXPECT_TRUE(refs.UpdatePositions(FakeUpdater{ { StrRange{ 0, 1 }, StrRange{ 2, 3 }, StrRange{ 4, 5 } } })); + EXPECT_EQ(refs.get().at(0).position, StrRange(0, 1)); + EXPECT_EQ(refs.get().at(1).position, StrRange(2, 3)); + EXPECT_EQ(refs.get().at(2).position, StrRange(4, 5)); + + refs.Resolve(complexRefStr); + EXPECT_TRUE(refs.UpdatePositions(FakeUpdater{ { StrRange{ 0, 4 }, StrRange{ 5, 10 }, StrRange{ 11, 15 } } })); + EXPECT_EQ(refs.get().at(0).position, StrRange(0, 4)); + EXPECT_EQ(refs.get().at(1).position, StrRange(5, 10)); + EXPECT_EQ(refs.get().at(2).position, StrRange(11, 15)); +} + +TEST_F(UTRefsManager, OutputRefs) { + using ccl::operator""_c17; + + EXPECT_TRUE(empty(refs.OutputRefs({}, {}))); + EXPECT_TRUE(empty(refs.OutputRefs({}, StrRange{ 0, 10 }))); + + refs.Resolve({}); + EXPECT_TRUE(empty(refs.OutputRefs({}, {}))); + + refs.Resolve(u8"\u212Cabc"_c17); + EXPECT_EQ(refs.OutputRefs(u8"\u212Cabc"_c17), u8"\u212Cabc"_c17); + + const auto normStr = refs.Resolve(complexRefStr); + EXPECT_EQ(refs.OutputRefs(normStr), complexRefStr); +} + +TEST_F(UTRefsManager, OutputRefsRange) { + const auto normStr = refs.Resolve(complexRefStr); + + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 27 }), complexRefStr); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 2 }), "42"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 0 }), ""); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 26, 27 }), "5"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 27, 28 }), ""); + + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 7 }), "42 @{X1|sing,nomn}"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 6 }), "42 @{X1|sing,nomn}"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 5 }), "42 @{X1|sing,nomn}"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 4 }), "42 "); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 0, 3 }), "42 "); + + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 3, 10 }), "@{X1|sing,nomn} 43"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 4, 10 }), "@{X1|sing,nomn} 43"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 5, 10 }), "@{X1|sing,nomn} 43"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 6, 10 }), " 43"); + EXPECT_EQ(refs.OutputRefs(normStr, StrRange{ 7, 10 }), " 43"); +} \ No newline at end of file diff --git a/ccl/cclLang/test/src/testTextProcessor.cpp b/ccl/cclLang/test/src/testTextProcessor.cpp new file mode 100644 index 0000000..0ec1b00 --- /dev/null +++ b/ccl/cclLang/test/src/testTextProcessor.cpp @@ -0,0 +1,38 @@ +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "ccl/lang/TextProcessor.h" +#include "ccl/lang/Literals.h" + +using ccl::lang::operator""_form; + +class UTTextProcessor : public ::testing::Test { +protected: + using TextProcessor = ccl::lang::TextProcessor; + using Morphology = ccl::lang::Morphology; + + TextProcessor processor{}; +}; + +TEST_F(UTTextProcessor, DefaultImplementations) { + EXPECT_EQ(processor.Inflect("invalid", Morphology{}), "invalid"); + EXPECT_EQ(processor.Inflect("term", "sing,nomn"_form), "term"); + EXPECT_EQ(processor.InflectDependant("", ""), ""); + EXPECT_EQ(processor.InflectDependant("invalid", ""), "invalid"); +} + +TEST_F(UTTextProcessor, IsSubstr) { + EXPECT_TRUE(processor.IsSubstr("", "")); + EXPECT_TRUE(processor.IsSubstr("", "42")); + EXPECT_TRUE(processor.IsSubstr("4", "42")); + EXPECT_TRUE(processor.IsSubstr("2", "42")); + EXPECT_TRUE(processor.IsSubstr("42", "42")); + EXPECT_TRUE(processor.IsSubstr("test", "Test")); + EXPECT_TRUE(processor.IsSubstr("T?est", "Test")); + EXPECT_TRUE(processor.IsSubstr("T?est", "est")); + EXPECT_TRUE(processor.IsSubstr("?est", "?est")); + EXPECT_TRUE(processor.IsSubstr("?est", "?esT")); + EXPECT_FALSE(processor.IsSubstr("42", "")); + EXPECT_FALSE(processor.IsSubstr("[a-b][a", "abba")); +} \ No newline at end of file diff --git a/ccl/cclLang/test/unity/cclLangTest.cpp b/ccl/cclLang/test/unity/cclLangTest.cpp new file mode 100644 index 0000000..a0ff401 --- /dev/null +++ b/ccl/cclLang/test/unity/cclLangTest.cpp @@ -0,0 +1,12 @@ +//! Unity build for cclLangTest + +#define GTEST_LANG_CXX11 1 + +#include "gtest/gtest.h" + +#include "../src/testLexicalTerm.cpp" +#include "../src/testManagedText.cpp" +#include "../src/testMorphology.cpp" +#include "../src/testReference.cpp" +#include "../src/testRefsManager.cpp" +#include "../src/testTextProcessor.cpp" \ No newline at end of file diff --git a/ccl/cclLang/test/utils/FakeTermContext.hpp b/ccl/cclLang/test/utils/FakeTermContext.hpp new file mode 100644 index 0000000..9a0ad4d --- /dev/null +++ b/ccl/cclLang/test/utils/FakeTermContext.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "ccl/lang/LexicalTerm.h" +#include "ccl/lang/EntityTermContext.hpp" + +class FakeContext : public ccl::lang::EntityTermContext { + std::unordered_map terms{}; + +public: + void Clear() noexcept { terms.clear(); } + void Insert(const std::string& entity, const ccl::lang::LexicalTerm& term) { + terms.emplace(std::pair{ entity , term }); + } + + bool Contains(const std::string& entity) const override { + return terms.contains(entity); + } + const ccl::lang::LexicalTerm* At(const std::string& entity) const override { + if (!Contains(entity)) { + return nullptr; + } else { + return &terms.at(entity); + } + } +}; \ No newline at end of file diff --git a/ccl/cclLang/test/utils/FakeTextProcessor.hpp b/ccl/cclLang/test/utils/FakeTextProcessor.hpp new file mode 100644 index 0000000..7a162ff --- /dev/null +++ b/ccl/cclLang/test/utils/FakeTextProcessor.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "ccl/lang/TextEnvironment.h" + +struct FakeTextProcessor : ccl::lang::TextProcessor { + static inline std::string x1Ref = R"(@{X1|nomn|sing})"; + +}; diff --git a/ccl/cclLang/test/utils/MockTextProcessor.hpp b/ccl/cclLang/test/utils/MockTextProcessor.hpp new file mode 100644 index 0000000..03eda9c --- /dev/null +++ b/ccl/cclLang/test/utils/MockTextProcessor.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "ccl/lang/TextProcessor.h" + +namespace tccl { + +using ccl::lang::Morphology; +using ccl::lang::TextProcessor; + +struct MockTextProcessor : TextProcessor { + enum CallType : uint8_t { + INFLECT, + DEPENDANT + }; + + struct CallEntry { + CallType type; + std::string targetText; + std::optional form{}; + std::optional mainText{}; + }; + + using InflectDB = std::vector, std::string>>; + using DependantDB = std::vector, std::string>>; + + mutable std::vector log{}; + mutable InflectDB inflections{}; + mutable DependantDB substitutes{}; + + void ClearLog() noexcept { + log.clear(); + } + + void ClearAll() noexcept { + inflections.clear(); + substitutes.clear(); + log.clear(); + } + + void AddInflection(std::string target,Morphology morpho, std::string result) { + inflections.emplace_back(std::pair(std::move(target), std::move(morpho)), std::move(result)); + } + + void AddCollaboration(std::string dependant, std::string main, std::string result) { + substitutes.emplace_back(std::pair(std::move(dependant), std::move(main)), std::move(result)); + } + + [[nodiscard]] std::string Inflect(const std::string& target, const Morphology& form) const override { + log.emplace_back(CallEntry{INFLECT, target, form, {}}); + const auto itr = + std::find_if(begin(inflections), end(inflections), + [&target, &form](const auto& v) { return v.first.first == target && v.first.second == form; }); + if (itr != end(inflections)) { + return itr->second; + } else { + return target; + } + } + + [[nodiscard]] std::string InflectDependant(const std::string& dependant, const std::string& main) const override { + log.emplace_back(CallEntry{DEPENDANT, dependant, std::nullopt, main}); + const auto itr = + std::find_if(begin(substitutes), end(substitutes), + [&dependant, &main](const auto& v) { return v.first.first == dependant && v.first.second == main; }); + if (itr != end(substitutes)) { + return itr->second; + } else { + return dependant; + } + } + //std::string ApplyForm(const std::string& nominal, ccl::lang::Termform termForm) const override { + // callLog.emplace_back(CallEntry{ APPLYFORM, nominal, termForm }); + // if (std::empty(nominal)) { + // return nominal; + // } else { + // return "RESOLVED_TERM"; + // } + //} + //std::string ApplyFormGender(const std::string& word, + // ccl::lang::Termform form, + // ccl::lang::Gender gender) const override { + // callLog.emplace_back(CallEntry{ APPLYGENDER, word, form, gender }); + // if (std::empty(word)) { + // return word; + // } else { + // return "RESOLVED_COMPANION"; + // } + //} +}; + +} // namespace tccl diff --git a/ccl/cclLang/test/utils/RefHelper.hpp b/ccl/cclLang/test/utils/RefHelper.hpp new file mode 100644 index 0000000..fade3ed --- /dev/null +++ b/ccl/cclLang/test/utils/RefHelper.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "ccl/lang/Reference.h" + +namespace tccl { + +inline std::string EntityRef(const std::string& cstName, + const ccl::lang::Morphology form = ccl::lang::Morphology{ ccl::lang::Grammem::nomn, ccl::lang::Grammem::sing }) { + const ccl::lang::EntityRef ref{ cstName, form }; + return ref.ToString(); +} + +} // namespace tccl \ No newline at end of file diff --git a/ccl/cclLang/unity/cclLang.cpp b/ccl/cclLang/unity/cclLang.cpp new file mode 100644 index 0000000..d624f6c --- /dev/null +++ b/ccl/cclLang/unity/cclLang.cpp @@ -0,0 +1,10 @@ +//! Unity build for cclLang + +#include "../src/LexicalTerm.cpp" +#include "../src/ManagedText.cpp" +#include "../src/Reference.cpp" +#include "../src/RefsManager.cpp" +#include "../src/Morphology.cpp" +#include "../src/TextEnvironment.cpp" +#include "../src/TextProcessor.cpp" +#include "../src/Literals.cpp" \ No newline at end of file diff --git a/ccl/cmake/CXXTargets.cmake b/ccl/cmake/CXXTargets.cmake new file mode 100644 index 0000000..dbbf945 --- /dev/null +++ b/ccl/cmake/CXXTargets.cmake @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.23) + +if(TARGET ccl_CXXwarnings) + return() +endif() + +## +## Compiler options +## +add_library(ccl_CXXwarnings INTERFACE) +add_library(ccl_CXXoptions INTERFACE) + +target_compile_features(ccl_CXXoptions INTERFACE cxx_std_20) + +if(CC_UseSanitizers AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(ccl_CXXoptions + INTERFACE + -fsanitize=address + -fsanitize=undefined + ) + target_link_libraries(ccl_CXXoptions + INTERFACE + -fsanitize=address + -fsanitize=undefined + ) +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(ccl_CXXwarnings + INTERFACE + -Wall + -Werror + -Wextra + -Wextra-semi-stmt + -Wshadow + -Wconversion + -Wold-style-cast + -Wunused + -Woverloaded-virtual + -Wnull-dereference + -Wdouble-promotion + -Wno-invalid-token-paste + -Wno-unknown-pragmas + -Wno-unused-variable + -Wformat=2 + ) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(ccl_CXXwarnings + INTERFACE + -Wall + -Werror + -Wmisleading-indentation + -Wduplicated-cond + -Wno-unknown-pragmas + -Wduplicated-branches + -Wuseless-cast + -Wlogical-op + -fexceptions + ) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_compile_options(ccl_CXXoptions + INTERFACE + /Zi + ) + target_compile_options(ccl_CXXwarnings + INTERFACE + /permissive- + /W4 + ) +endif() \ No newline at end of file diff --git a/ccl/conanfile.txt b/ccl/conanfile.txt new file mode 100644 index 0000000..a345ddf --- /dev/null +++ b/ccl/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +gtest/1.14.0 + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout \ No newline at end of file diff --git a/ccl/core/ConceptLibrary.vcxproj b/ccl/core/ConceptLibrary.vcxproj new file mode 100644 index 0000000..e4dd2e1 --- /dev/null +++ b/ccl/core/ConceptLibrary.vcxproj @@ -0,0 +1,259 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.0 + {B0ABA27B-9D39-4B48-9977-AFF20925B309} + Win32Proj + StaticLibrary + ConceptLibrary + 10.0 + ConceptCoreLibrary + v143 + Unicode + + + + true + + + false + true + + + true + + + true + + + + + + + + false + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + $(ProjectName) + + + true + ..\..\output\lib\x86\ + build\x86\$(Configuration)\ + $(ProjectName)d + + + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + $(ProjectName)d + + + ..\..\output\lib\x64\ + build\x64\$(Configuration)\ + $(ProjectName) + + + + include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include + NotUsing + Level4 + MaxSpeed + true + true + true + _LIB;NDEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + $(OutDir)$(ProjectName).pdb + $(IntDir) + $(IntDir) + $(IntDir)obj\ + true + true + /bigobj %(AdditionalOptions) + + + Windows + true + true + true + + + xcopy /y /s /q /i include ..\..\output\include + + + + + include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include + NotUsing + Level4 + Disabled + true + _LIB;_DEBUG;%(PreprocessorDefinitions) + true + stdcpplatest + Default + $(OutDir)$(ProjectName)d.pdb + $(IntDir) + $(IntDir) + $(IntDir)obj\ + true + true + /bigobj %(AdditionalOptions) + + + Windows + true + + + xcopy /y /s /q /i include ..\..\output\include + + + + + stdcpplatest + include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include + EditAndContinue + true + Level4 + true + true + Disabled + false + _DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + true + $(IntDir)obj\ + $(OutDir)$(ProjectName)d.pdb + true + /bigobj %(AdditionalOptions) + + + xcopy /y /s /q /i include ..\..\output\include + + + + + stdcpplatest + include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include + Level4 + true + true + true + false + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + $(IntDir)obj\ + $(OutDir)$(ProjectName).pdb + true + /bigobj %(AdditionalOptions) + + + xcopy /y /s /q /i include ..\..\output\include + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {7e1d5338-f819-4c96-b461-9eaab8d02e1d} + + + {76b03803-56cc-47c2-a8f0-2241fcaf2898} + + + {a8529c63-42f5-43e6-97b8-2ec83f23e1f9} + + + + \ No newline at end of file diff --git a/ccl/core/ConceptLibrary.vcxproj.filters b/ccl/core/ConceptLibrary.vcxproj.filters new file mode 100644 index 0000000..d4fb78a --- /dev/null +++ b/ccl/core/ConceptLibrary.vcxproj.filters @@ -0,0 +1,252 @@ + + + + + {86d3c4ce-8b73-446b-ae23-3c51e5321065} + + + {bb109e85-4730-40c3-8cf6-4cf4a3c7111d} + + + {afefed49-4a72-4a1d-87f0-26c3b8f3f1e9} + + + {5c6e9f8c-3112-47da-9118-ecfbaa836009} + + + {dafdb290-2760-4574-bf2e-86b94008efe7} + + + {1d5f943e-0673-47a8-b4ab-ef179e4c3dd1} + + + {2bd129f8-604d-4b83-affd-8f322bbff657} + + + {5de97bf2-566e-46c1-9b21-9ceacac19749} + + + {0a673bb0-fb75-4cc4-8fd7-1b1d033a699a} + + + {166b33ed-84a5-4040-8398-983a541cc3db} + + + {3b955deb-294b-4000-bb01-4a043fdfbf38} + + + {b2207c2a-30f0-424c-bfe2-f81eeca2949d} + + + + + 02 env + + + 01 tools + + + 01 tools + + + 04 ops\01 RSOps + + + 04 ops\01 RSOps + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 04 ops + + + 04 ops\01 RSOps + + + 01 tools + + + 03 semantic\04 RSForm + + + 03 semantic\04 RSForm + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\04 RSForm + + + 03 semantic\03 RSCore + + + 03 semantic\03 RSCore + + + 03 semantic\03 RSCore + + + 03 semantic\01 Schema + + + 03 semantic\01 Schema + + + 03 semantic\02 Thesaurus + + + 03 semantic\02 Thesaurus + + + 03 semantic\03 RSCore + + + 06 API + + + + + 02 env + + + 02 env + + + 01 tools + + + 01 tools + + + 04 ops\01 RSOps + + + 04 ops\01 RSOps + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 05 oss + + + 04 ops + + + 01 tools + + + 01 tools + + + 03 semantic + + + 03 semantic + + + 03 semantic\04 RSForm + + + 03 semantic\04 RSForm + + + 03 semantic\04 RSForm + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\05 RSModel + + + 03 semantic\03 RSCore + + + 03 semantic\02 Thesaurus + + + 03 semantic\01 Schema + + + 03 semantic\01 Schema + + + 03 semantic\02 Thesaurus + + + 03 semantic\03 RSCore + + + 03 semantic\03 RSCore + + + 03 semantic\03 RSCore + + + 03 semantic\01 Schema + + + 03 semantic\03 RSCore + + + 04 ops\01 RSOps + + + 06 API + + + \ No newline at end of file diff --git a/ccl/core/RunCoverage.bat b/ccl/core/RunCoverage.bat new file mode 100644 index 0000000..1a9fb69 --- /dev/null +++ b/ccl/core/RunCoverage.bat @@ -0,0 +1,3 @@ +OpenCppCoverage --sources "%~dp0src" --sources "%~dp0header" --sources "%~dp0include" --modules "%~dp0build\Debug\ConceptCoreLibraryd.lib" --modules "%~dp0test\build\Debug\cclTest.exe" --excluded_line_regex "\s*\} else \{.*" --excluded_line_regex "\s*\}\s*" --excluded_line_regex "\s*\sthrow *" --excluded_line_regex "\sassert\(.*" --excluded_sources "rsparserimpl.cpp" --excluded_sources "rsparserimpl.y" --excluded_sources "stack.hh" -- %~dp0test\build\Debug\CCLTest.exe + +pause \ No newline at end of file diff --git a/ccl/core/include/ccl/Operation.hpp b/ccl/core/include/ccl/Operation.hpp new file mode 100644 index 0000000..4cd5a23 --- /dev/null +++ b/ccl/core/include/ccl/Operation.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/cclMeta.hpp" +#include "ccl/Source.hpp" + +namespace ccl::ops { + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +//! Operation status enumeration +enum class Status : uint32_t { + undefined = 2, + defined = 3, + done = 4, + outdated = 5, // Требуется пересинтез + broken = 7, // Требуется переопределение операции +}; + +//! Operation type enumeration +enum class Type : uint32_t { + tba = 0, + rsMerge = 4, // Слияние двух РС-форм в одну + rsSynt = 8, // Обобщенный синтез +}; + +static constexpr bool HasOptions(Type type) noexcept { return type == Type::rsSynt; } + +//! Abstract options of operation +class Options { +public: + virtual ~Options() noexcept = default; + +protected: + Options() = default; + Options(const Options&) = default; + Options& operator=(const Options&) = default; + Options(Options&&) noexcept = default; + Options& operator=(Options&&) noexcept = default; + +public: + [[nodiscard]] virtual bool IsEqualTo(const Options& /*opt2*/) const = 0; +}; + +//! Abstract translation data +using TranslationData = std::vector; + +using Args = std::vector; +using ArgsInfo = std::vector; + +//! Operation signature +struct Signature { + src::DataType result{}; + ArgsInfo args{}; +}; + +//! Operation call +struct Call { + Type type{ Type::tba }; + const Options* params{ nullptr }; + Args args{}; + + [[nodiscard]] ArgsInfo Info() const { + auto result = ArgsInfo{}; + for (const auto& arg : args) { + result.emplace_back(arg == nullptr ? src::DataType::tba : arg->Type()); + } + return result; + } +}; + +//! Operation result +struct Result { + meta::UniqueCPPtr value{ nullptr }; + meta::UniqueCPPtr translation{ nullptr }; +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl::ops \ No newline at end of file diff --git a/ccl/core/include/ccl/Source.hpp b/ccl/core/include/ccl/Source.hpp new file mode 100644 index 0000000..a2dbd95 --- /dev/null +++ b/ccl/core/include/ccl/Source.hpp @@ -0,0 +1,196 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/cclChange.hpp" +#include "ccl/cclMeta.hpp" + +namespace ccl::src { + +//! Data type enumeration +enum class DataType : uint32_t { tba = 0, rsSchema }; + +//! Source type enumeration +enum class SrcType : uint32_t { tba = 0, rsDoc }; + +//! Abstract data stream +class DataStream { +public: + virtual ~DataStream() noexcept = default; + + DataStream& operator=(const DataStream&) = delete; + DataStream& operator=(DataStream&&) = delete; + +protected: + DataStream() = default; + DataStream(const DataStream&) = default; + DataStream(DataStream&&) noexcept = default; + + +public: + enum class Attribute : uint32_t { + title, alias, comment + }; + + using ValueType = std::string; + + struct AttrValue { + Attribute type{}; + ValueType value{}; + }; + + [[nodiscard]] virtual DataType Type() const noexcept = 0; +}; + +template< + typename T, + typename = std::enable_if_t> +> +const T* CastData(const DataStream* data) noexcept { + return dynamic_cast(data); +} + +//! Abstract data source +class Source { + bool isClaimed{ false }; + +public: + virtual ~Source() noexcept = default; + +protected: + Source() = default; + Source(const Source&) = default; + Source& operator=(const Source&) noexcept = default; + Source& operator=(Source&&) noexcept = default; + Source(Source&&) = default; + +public: + [[nodiscard]] virtual change::Hash CoreHash() const = 0; + [[nodiscard]] virtual change::Hash FullHash() const = 0; + [[nodiscard]] virtual SrcType Type() const noexcept = 0; + + virtual bool WriteData(meta::UniqueCPPtr /*data*/) = 0; + [[nodiscard]] virtual const DataStream* ReadData() const = 0; + [[nodiscard]] virtual DataStream* AccessData() = 0; + + [[nodiscard]] bool IsClaimed() const noexcept { return isClaimed; } + void Claim() noexcept { isClaimed = true; } + void ReleaseClaim() noexcept { isClaimed = false; } +}; + +//! Source descriptor +struct Descriptor { + SrcType type{ SrcType::tba }; + std::u8string name{}; + + explicit Descriptor(SrcType type = SrcType::tba, std::u8string name = {}) noexcept + : type{ type }, name{ std::move(name) } {} + + bool operator==(const Descriptor& rhs) const noexcept { return type == rhs.type && name == rhs.name; } + bool operator!=(const Descriptor& rhs) const noexcept { return !(*this == rhs); } +}; + +//! Source handle +struct Handle { + Source* src{ nullptr }; + Descriptor desc{}; + + change::Hash coreHash{ 0 }; + change::Hash fullHash{ 0 }; + +public: + Handle() = default; + + explicit Handle(SrcType type) noexcept + : desc{ type, std::u8string{} } {} + +public: + [[nodiscard]] bool empty() const noexcept { + return src == nullptr && std::empty(desc.name); + } + void UpdateHashes() { + coreHash = src == nullptr ? coreHash : src->CoreHash(); + fullHash = src == nullptr ? fullHash : src->FullHash(); + } + void DiscardSrc() noexcept { + src = nullptr; + desc.name.clear(); + coreHash = 0; + fullHash = 0; + } +}; + +//! Abstract source callback +class SourceCallback { +public: + virtual ~SourceCallback() noexcept = default; + +protected: + SourceCallback() = default; + SourceCallback(const SourceCallback&) = default; + SourceCallback& operator=(const SourceCallback&) = default; + SourceCallback(SourceCallback&&) noexcept = default; + SourceCallback& operator=(SourceCallback&&) noexcept = default; + +public: + [[nodiscard]] virtual change::Usage QueryEntityIsUsed(const src::Source& /*from*/, EntityUID /*entity*/) const = 0; + [[nodiscard]] virtual bool IsConnectedWith(const src::Source& /*src*/) const = 0; +}; + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +//! Callback manager base class +class CallbackManager { + std::vector callbacks{}; + +public: + bool AddCallback(SourceCallback& newCB) { + if (std::find(begin(callbacks), end(callbacks), &newCB) != end(callbacks)) { + return false; + } else { + callbacks.emplace_back(&newCB); + return true; + } + } + + void RemoveCallback(const SourceCallback& cb) { + if (const auto item = std::find(begin(callbacks), end(callbacks), &cb); + item != end(callbacks)) { + callbacks.erase(item); + } + } + + void ImportCallbacksFrom(CallbackManager& rhs) { + if (this != &rhs) { + for (auto& cb : rhs.callbacks) { + AddCallback(*cb); + } + } + } + + [[nodiscard]] bool QuerySrcUse(const src::Source& src) const { + return std::any_of(begin(callbacks), end(callbacks), + [&](const auto& callback) { + return callback->IsConnectedWith(src); + }); + } + + [[nodiscard]] change::Usage QueryEntityUse(const src::Source& from, EntityUID entity) const { + change::Usage result = change::Usage::notUsed; + for (const auto& callback : callbacks) { + const auto curStatus = callback->QueryEntityIsUsed(from, entity); + if (static_cast(result) < static_cast(curStatus)) { + result = curStatus; + } + } + return result; + } +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl::src \ No newline at end of file diff --git a/ccl/core/include/ccl/api/RSFormJA.h b/ccl/core/include/ccl/api/RSFormJA.h new file mode 100644 index 0000000..7e82630 --- /dev/null +++ b/ccl/core/include/ccl/api/RSFormJA.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ccl/semantic/RSForm.h" + +namespace ccl::api { + +static constexpr int JSON_IDENT = 4; +std::string ParseExpression(const std::string& expression, rslang::Syntax syntaxHint = rslang::Syntax::UNDEF); + +//! JSON accessor wrapper for RSForm object +class RSFormJA { +private: + std::unique_ptr schema{}; + +private: + RSFormJA() noexcept = default; + +public: + [[nodiscard]] const semantic::RSForm& data() const noexcept; + [[nodiscard]] semantic::RSForm& data() noexcept; + + [[nodiscard]] static RSFormJA FromData(semantic::RSForm&& data); + [[nodiscard]] static RSFormJA FromJSON(std::string_view json); + [[nodiscard]] std::string ToJSON() const; + [[nodiscard]] std::string ToMinimalJSON() const; + + [[nodiscard]] std::string CheckExpression(const std::string& text, rslang::Syntax syntaxHint = rslang::Syntax::UNDEF) const; +}; + +} // namespace ccl::api diff --git a/ccl/core/include/ccl/env/SourceManager.hpp b/ccl/core/include/ccl/env/SourceManager.hpp new file mode 100644 index 0000000..d95ccfd --- /dev/null +++ b/ccl/core/include/ccl/env/SourceManager.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include "ccl/Source.hpp" + +namespace ccl { + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 ) // Note: do not warn if default implementation might be noexcept +#endif + +//! Abstract source manager +class SourceManager : public src::CallbackManager, public types::Observable { +public: + SourceManager() = default; + virtual ~SourceManager() noexcept = default; + + SourceManager(const SourceManager&) = delete; + SourceManager& operator=(const SourceManager&) = delete; + +public: + struct SrcMessage : types::Message { + explicit SrcMessage(src::Descriptor srcID) noexcept + : srcID{ std::move(srcID) } {} + + [[nodiscard]] uint32_t Type() const noexcept override { return srcCode; } + src::Descriptor srcID; + }; + + struct SrcOpened : SrcMessage { using SrcMessage::SrcMessage; }; + struct SrcClosed : SrcMessage { using SrcMessage::SrcMessage; }; + struct SrcChanged : SrcMessage { using SrcMessage::SrcMessage; }; + +public: + void OnSourceOpen(const src::Source& src) { Notify(SrcOpened{ GetDescriptor(src) }); } + void OnSourceClose(const src::Source& src) { Notify(SrcClosed{ GetDescriptor(src) }); } + void OnSourceChange(const src::Source& src) { Notify(SrcChanged{ GetDescriptor(src) }); } + + [[nodiscard]] virtual bool TestDomain(const src::Descriptor& /*global*/, + const std::u8string& /*domain*/) const { + return false; + } + [[nodiscard]] virtual src::Descriptor Convert2Local(const src::Descriptor& /*global*/, + const std::u8string& /*domain*/) const { + return src::Descriptor{}; + } + [[nodiscard]] virtual src::Descriptor Convert2Global(const src::Descriptor& /*local*/, + const std::u8string& /*domain*/) const { + return src::Descriptor{}; + } + [[nodiscard]] virtual src::Descriptor CreateLocalDesc(src::SrcType type, std::u8string localName) const { + return src::Descriptor{ type, localName }; + } + [[nodiscard]] virtual src::Source* Find(const src::Descriptor& /*desc*/) { + return nullptr; + } + [[nodiscard]] virtual src::Descriptor GetDescriptor(const src::Source& /*src*/) const + { return src::Descriptor{}; + } + virtual bool ChangeDescriptor(const src::Descriptor& /*desc*/, const src::Descriptor& /*newDesc*/) { + return false; + } + [[nodiscard]] virtual src::Source* CreateNew(const src::Descriptor& /*desc*/) { + return nullptr; + } + [[nodiscard]] virtual src::Source* Open(const src::Descriptor& /*desc*/) { + return nullptr; + } + virtual void Close(src::Source& /*src*/) {} + virtual bool SaveState(src::Source& /*src*/) { + return false; + } + virtual void Discard(const src::Descriptor& /*desc*/) {} +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +} // namespace ccl \ No newline at end of file diff --git a/ccl/core/include/ccl/env/cclEnvironment.h b/ccl/core/include/ccl/env/cclEnvironment.h new file mode 100644 index 0000000..fe1a521 --- /dev/null +++ b/ccl/core/include/ccl/env/cclEnvironment.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ccl/env/SourceManager.hpp" + +#include + +namespace ccl { + +//! Enivroment configuration - !Global state! +class Environment final { + std::unique_ptr sources{ std::make_unique() }; + +public: + [[nodiscard]] static Environment& Instance() noexcept; + + [[nodiscard]] static SourceManager& Sources() noexcept { return *Instance().sources; } + [[nodiscard]] static std::random_device& RNG(); + + [[nodiscard]] static std::string_view VersionInfo() noexcept; + + void SetSourceManager(std::unique_ptr newSources); +}; + +} // namespace ccl \ No newline at end of file diff --git a/ccl/core/include/ccl/ops/EquationOptions.h b/ccl/core/include/ccl/ops/EquationOptions.h new file mode 100644 index 0000000..e4b3ddf --- /dev/null +++ b/ccl/core/include/ccl/ops/EquationOptions.h @@ -0,0 +1,67 @@ +#pragma once + +#include "ccl/Operation.hpp" +#include "ccl/Entity.hpp" + +namespace ccl::ops { + +//! Options for single entity equation +struct Equation { + enum class Mode : uint8_t { + keepHier = 1, + keepDel = 2, + createNew = 3, + }; + + Equation::Mode mode{ Equation::Mode::keepHier }; + std::string arg{}; + + Equation() = default; + explicit Equation(Equation::Mode mode, std::string arg) noexcept + : mode{ mode }, arg{ std::move(arg) } {} + + bool operator==(const Equation& rhs) const noexcept { + return mode == rhs.mode && arg == rhs.arg; + } + bool operator!=(const Equation& rhs) const noexcept { + return mode != rhs.mode || arg != rhs.arg; + } +}; + +//! Options for equation operation +class EquationOptions : public Options { +public: + using Props = std::unordered_map; + +private: + EntityTranslation translation{}; + Props properties{}; + +public: + EquationOptions() = default; + + explicit EquationOptions(EntityUID key, EntityUID val, const Equation& params = {}); + +public: + using ConstIter = EntityTranslation::ConstIter; + using size_type = EntityTranslation::size_type; + + [[nodiscard]] bool IsEqualTo(const Options& opt2) const override; + + [[nodiscard]] ConstIter begin() const noexcept { return std::begin(translation); } + [[nodiscard]] ConstIter end() const noexcept { return std::end(translation); } + [[nodiscard]] size_type size() const noexcept { return std::size(translation); } + [[nodiscard]] bool empty() const noexcept { return std::empty(translation); } + + [[nodiscard]] const Equation& PropsFor(EntityUID key) const; + + [[nodiscard]] bool ContainsValue(EntityUID value) const; + [[nodiscard]] bool ContainsKey(EntityUID key) const; + + void Insert(EntityUID key, EntityUID val, const Equation& params = {}); + void Erase(EntityUID key) noexcept; + bool SwapKeyVal(EntityUID key); + void SubstituteValues(const EntityTranslation& idSubstitutes); +}; + +} // namespace ccl::ops \ No newline at end of file diff --git a/ccl/core/include/ccl/ops/RSAggregator.h b/ccl/core/include/ccl/ops/RSAggregator.h new file mode 100644 index 0000000..85d7aba --- /dev/null +++ b/ccl/core/include/ccl/ops/RSAggregator.h @@ -0,0 +1,33 @@ +#pragma once + +#include "ccl/semantic/RSForm.h" + +namespace ccl::ops { + +//! Aggregation manager for versions of RSForm object +class RSAggregator { + semantic::RSForm& output; + const semantic::RSForm* prevOutput{ nullptr }; + + EntityTranslation translation{}; + StrSubstitutes nameSubstitutes{}; + VectorOfEntities insertedCsts{}; + +public: + explicit RSAggregator(semantic::RSForm& newShema) + : output{ newShema } {} + +public: + std::optional Merge(const semantic::RSForm& previous, const EntityTranslation& oldToNew); + +private: + void Clear() noexcept; + bool PrepareSubstitutes(); + void TransferNew(); + void TransferIheritedData(); + void UpdateReferences(); + + [[nodiscard]] std::optional TransferCst(EntityUID target, semantic::ListIterator insertWhere); +}; + +} // namespace ccl::ops \ No newline at end of file diff --git a/ccl/core/include/ccl/ops/RSEquationProcessor.h b/ccl/core/include/ccl/ops/RSEquationProcessor.h new file mode 100644 index 0000000..0f2841b --- /dev/null +++ b/ccl/core/include/ccl/ops/RSEquationProcessor.h @@ -0,0 +1,44 @@ +#pragma once + +#include "ccl/rslang/TypeContext.hpp" +#include "ccl/rslang/Typification.h" +#include "ccl/ops/EquationOptions.h" +#include "ccl/Substitutes.hpp" + +namespace ccl::semantic { class RSForm; } + +namespace ccl::ops { + +//! Constituents equation processor +class RSEquationProcessor { + semantic::RSForm& schema; + EntityTranslation translation{}; + + mutable const EquationOptions* equations{ nullptr }; + mutable StrSubstitutes nameSubstitutes{}; + +public: + explicit RSEquationProcessor(semantic::RSForm& schema); + +public: + [[nodiscard]] bool Evaluate(const EquationOptions& options) const; + [[nodiscard]] bool Execute(const EquationOptions& options); + [[nodiscard]] const EntityTranslation& Translation() const noexcept { return translation; } + +private: + void Clear() noexcept; + void ClearMutable() const noexcept; + + bool ResolveCstAndPrecheck() const; + bool PrecheckFor(EntityUID key, EntityUID value) const; + + bool CheckNonBasicEquations() const; + + void ChangeEquatedCsts(); + void RemoveEquatedCsts(); + void UpdateExpressions(); + + [[nodiscard]] rslang::ExpressionType Evaluate(EntityUID uid) const; +}; + +} // namespace ccl::ops \ No newline at end of file diff --git a/ccl/core/include/ccl/ops/RSOperations.h b/ccl/core/include/ccl/ops/RSOperations.h new file mode 100644 index 0000000..6113ccf --- /dev/null +++ b/ccl/core/include/ccl/ops/RSOperations.h @@ -0,0 +1,116 @@ +#pragma once + +#include "ccl/semantic/RSForm.h" +#include "ccl/Operation.hpp" +#include "ccl/ops/EquationOptions.h" + +namespace ccl::ops { + +//! Binary synthesis of RSForms +class BinarySynthes { + const semantic::RSForm& operand1; + const semantic::RSForm& operand2; + + EquationOptions equations; + + bool isCorrect{ false }; + std::unique_ptr resultSchema{ nullptr }; + TranslationData translations{}; + +public: + BinarySynthes(const semantic::RSForm& ks1, const semantic::RSForm& ks2, EquationOptions equations); + +public: + std::unique_ptr Execute(); + [[nodiscard]] const TranslationData& Translations() noexcept { return translations; } + [[nodiscard]] const EquationOptions& Equations() const noexcept; + [[nodiscard]] bool IsCorrectlyDefined() const noexcept; + +private: + void ResetResult(); + void PrecreateResult(); + [[nodiscard]] EquationOptions TranslateEquations() const; +}; + +//! Operation: Maximize part of RSForm +class OpMaxPart { + const semantic::RSForm& schema; + SetOfEntities arguments; + +public: + OpMaxPart(const semantic::RSForm& ks, SetOfEntities args) + : schema{ ks }, arguments{ std::move(args) } {} + +public: + std::unique_ptr Execute(); + [[nodiscard]] bool IsCorrectlyDefined() const; + +private: + [[nodiscard]] VectorOfEntities GetAllCstMaxPart() const; + [[nodiscard]] bool CheckCst(EntityUID target, const SetOfEntities& selList) const; +}; + +//! Operation: Extract basis from RSForm +class OpExtractBasis { + const semantic::RSForm& schema; + SetOfEntities arguments; + +public: + OpExtractBasis(const semantic::RSForm& ks, SetOfEntities args) + : schema{ ks }, arguments{ std::move(args) } {} + +public: + std::unique_ptr Execute(); + [[nodiscard]] bool IsCorrectlyDefined() const; +}; + +//! Operation: relativation +class OpRelativation { + const semantic::RSForm& operand; + const SetOfEntities ignoreOperand; + const EntityUID targetID; + bool isApplicable{ false }; + + std::unique_ptr resultSchema{ nullptr }; + + SetOfEntities ignoreResult{}; + EntityUID baseCst; + std::string baseStr{}; + + VectorOfEntities processOrder{}; + std::string baseID{}; + std::string termID{}; + std::unordered_map types{}; + std::unordered_set moifiedFuncs{}; + StrSubstitutes substitutes{}; + +public: + OpRelativation(const semantic::RSForm& ks, EntityUID target, const SetOfEntities& ignore = {}); + +public: + std::unique_ptr Execute(); + [[nodiscard]] static bool IsCorrectlyDefined(const semantic::RSForm& schema, EntityUID target, + const SetOfEntities& ignore = {}); + [[nodiscard]] bool IsCorrectlyDefined() const noexcept; + +private: + void ResetState() noexcept; + + void SetupCore(); + [[nodiscard]] SetOfEntities ExtractCore(); + void CreateProcessingOrder(const SetOfEntities& core); + [[nodiscard]] EntityUID PromoteBaseToStruct(EntityUID target); + [[nodiscard]] semantic::ConceptRecord CreateStructFrom(EntityUID base, const std::string& newName); + + void CreateUniqueIDs(); + + void CreateFunctions(); + [[nodiscard]] std::string GenerateTermFunc() const; + + void ModifyExpressions(); + [[nodiscard]] std::string UpdatedExpression(std::string_view input) const; + void UpdatedFunctionCalls(std::string& input) const; + [[nodiscard]] std::string UpdatedFunction(std::string_view input) const; +}; + +} // namespace ccl::ops \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/OSSchema.h b/ccl/core/include/ccl/oss/OSSchema.h new file mode 100644 index 0000000..fc3176f --- /dev/null +++ b/ccl/core/include/ccl/oss/OSSchema.h @@ -0,0 +1,137 @@ +#pragma once + +#include "ccl/tools/EntityGenerator.h" + +#include "ossGraphFacet.h" +#include "ossGridFacet.h" +#include "ossOperationsFacet.h" +#include "ossSourceFacet.h" + +namespace ccl::oss { + +class IteratorPict; +struct GridPosition; +struct OperationHandle; + +//! Operational synthesis schema +class OSSchema final : public change::ObservableMods, public types::Observer { + friend class IteratorPict; + friend class ossGridFacet; + friend class ossSourceFacet; + friend class ossOperationsFacet; + +public: + std::string title{}; + std::string comment{}; + +private: + using Storage = std::unordered_map; + Storage storage{}; + tools::EntityGenerator idGen{}; + + std::unique_ptr grid; + std::unique_ptr graph; + std::unique_ptr sources; + std::unique_ptr ops; + + class Callback; + std::unique_ptr callback{}; + +public: + ~OSSchema() noexcept override; + OSSchema(); + OSSchema(const OSSchema&) = delete; + OSSchema& operator=(const OSSchema&) = delete; + +public: + struct ErasePictMod : change::ModMessage { + PictID pid; + explicit ErasePictMod(const PictID pid) noexcept + : pid{ pid } {} + }; + struct SrcStatusMod : change::ModMessage {}; + struct SrcStateMod : change::ModMessage {}; + +public: + using size_type = Storage::size_type; + + void OnObserve(const types::Message& msg) override; + + [[nodiscard]] ossGridFacet& Grid() noexcept; + [[nodiscard]] const ossGridFacet& Grid() const noexcept; + [[nodiscard]] ossGraphFacet& Graph() noexcept; + [[nodiscard]] const ossGraphFacet& Graph() const noexcept; + [[nodiscard]] ossSourceFacet& Src() noexcept; + [[nodiscard]] const ossSourceFacet& Src() const noexcept; + [[nodiscard]] ossOperationsFacet& Ops() noexcept; + [[nodiscard]] const ossOperationsFacet& Ops() const noexcept; + + [[nodiscard]] size_type size() const noexcept; + [[nodiscard]] bool empty() const noexcept; + [[nodiscard]] bool Contains(PictID pict) const; + + [[nodiscard]] IteratorPict begin() const noexcept; + [[nodiscard]] IteratorPict end() const noexcept; + + [[nodiscard]] PictPtr operator()(PictID pid) const; + + PictPtr InsertBase(); + PictPtr InsertOperation(PictID operand1, PictID operand2); + + bool Erase(PictID target); + + void SetPictTitle(PictID target, const std::string& newValue); + void SetPictAlias(PictID target, const std::string& newValue); + void SetPictComment(PictID target, const std::string& newValue); + void SetPictLink(PictID target, const MediaLink& lnk); + + const Pict& LoadPict(Pict&& pict, GridPosition pos, const src::Handle& handle, std::unique_ptr params); + +private: + Pict* Access(PictID pid); + void InsertInternal(const Pict& pict, GridPosition pos, + const src::Handle& srcHandle, + std::unique_ptr opHandle); + + void OnCoreChange(PictID changedPict); + + //! OSS callback + class Callback : public src::SourceCallback { + OSSchema& oss; + + public: + explicit Callback(OSSchema& oss) noexcept + : oss{ oss } {} + + public: + [[nodiscard]] change::Usage QueryEntityIsUsed(const src::Source& from, EntityUID entity) const override; + [[nodiscard]] bool IsConnectedWith(const src::Source& src) const override; + }; +}; + +//! OSS iterator +class IteratorPict { + friend class OSSchema; + using Container = OSSchema::Storage; + Container::const_iterator iterator; + +private: + explicit IteratorPict(Container::const_iterator iter) noexcept; + +public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = Pict; + using difference_type = std::ptrdiff_t; + using pointer = const Pict*; + using reference = const Pict&; + + [[nodiscard]] bool operator==(const IteratorPict& iter2) const noexcept; + [[nodiscard]] bool operator!=(const IteratorPict& iter2) const noexcept { return !(*this == iter2); } + + IteratorPict& operator++() noexcept; + + [[nodiscard]] pointer operator->() const noexcept; + [[nodiscard]] reference operator*() const noexcept; +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/OperationProcessor.hpp b/ccl/core/include/ccl/oss/OperationProcessor.hpp new file mode 100644 index 0000000..c3a1e4e --- /dev/null +++ b/ccl/core/include/ccl/oss/OperationProcessor.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/Operation.hpp" + +namespace ccl::oss { + +//! Abstract OSS operations processor +class OperationsProcessor { +public: + virtual ~OperationsProcessor() noexcept = default; + OperationsProcessor() = default; + +protected: + OperationsProcessor(const OperationsProcessor&) = default; + OperationsProcessor& operator=(const OperationsProcessor&) = default; + OperationsProcessor(OperationsProcessor&&) noexcept = default; + OperationsProcessor& operator=(OperationsProcessor&&) noexcept = default; + +public: + [[nodiscard]] virtual std::optional + ResultingTypeFor(ops::Type /*operation*/, const ops::ArgsInfo& /*args*/) const = 0; + + [[nodiscard]] virtual bool CheckCall(const ops::Call& /*call*/) const = 0; + + [[nodiscard]] virtual std::optional Execute(const ops::Call& /*call*/) const = 0; + + [[nodiscard]] virtual EntityTranslation + CreateVersionTranslation(ops::Type /*operation*/, + const ops::TranslationData& /*oldT*/, + const ops::TranslationData& /*newT*/) const = 0; + + [[nodiscard]] virtual bool CheckTranslations(const ops::TranslationData& /*translations*/, + const src::DataStream& /*data*/) const = 0; + + [[nodiscard]] bool CanProcess(ops::Type operation, + const ops::ArgsInfo& args) const { + return ResultingTypeFor(operation, args).has_value(); + } + [[nodiscard]] bool CanProcess(const ops::Call& def) const { + return CanProcess(def.type, def.Info()); + } +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/Pict.hpp b/ccl/core/include/ccl/oss/Pict.hpp new file mode 100644 index 0000000..72bcb93 --- /dev/null +++ b/ccl/core/include/ccl/oss/Pict.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "ccl/Source.hpp" + +namespace ccl::oss { + +using PictID = uint32_t; + +//! Media hyperlink data +struct MediaLink { + std::string address{}; + std::string subAddr{}; + + [[nodiscard]] bool empty() const noexcept { + return std::empty(address); + } + bool operator==(const MediaLink& rhs) const noexcept { + return address == rhs.address && subAddr == rhs.subAddr; + } + bool operator!=(const MediaLink& rhs) const noexcept { + return address != rhs.address || subAddr != rhs.subAddr; + } +}; + +//! Pictogramm data structure +struct Pict { + PictID uid{ 0 }; + src::DataType dataType{ src::DataType::rsSchema }; + + std::string title{}; + std::string alias{}; + std::string comment{}; + + MediaLink lnk; + + Pict() = default; + explicit Pict(const PictID uid) noexcept + : uid{ uid } {} +}; + +using PictPtr = const Pict*; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/RSSynthesProcessor.h b/ccl/core/include/ccl/oss/RSSynthesProcessor.h new file mode 100644 index 0000000..f9d70c7 --- /dev/null +++ b/ccl/core/include/ccl/oss/RSSynthesProcessor.h @@ -0,0 +1,27 @@ +#pragma once + +#include "ccl/oss/OperationProcessor.hpp" + +namespace ccl::oss { + +//! RSForm synthesis processor for OSS +struct RSSProcessor : OperationsProcessor { + [[nodiscard]] std::optional + ResultingTypeFor(ops::Type /*operation*/, + const ops::ArgsInfo& args) const override; + + [[nodiscard]] bool CheckCall(const ops::Call& call) const override; + + [[nodiscard]] std::optional + Execute(const ops::Call& call) const override; + + [[nodiscard]] EntityTranslation + CreateVersionTranslation(ops::Type /*operation*/, + const ops::TranslationData& oldT, + const ops::TranslationData& newT) const override; + + [[nodiscard]] bool CheckTranslations(const ops::TranslationData& translations, + const src::DataStream& data) const override; +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/ossGraphFacet.h b/ccl/core/include/ccl/oss/ossGraphFacet.h new file mode 100644 index 0000000..30b298b --- /dev/null +++ b/ccl/core/include/ccl/oss/ossGraphFacet.h @@ -0,0 +1,44 @@ +#pragma once + +#include "ccl/oss/Pict.hpp" +#include "ccl/cclMeta.hpp" + +namespace ccl::oss { + +class OSSchema; + +class ossGraphFacet final : public meta::ConstFacet { + friend class OSSchema; + + using AdjacencyList = std::vector>; + AdjacencyList graph{}; + std::vector items{}; + +public: + explicit ossGraphFacet(const OSSchema& core) noexcept + : ConstFacet(core) {} + +public: + [[nodiscard]] std::vector ParentsOf(PictID pid) const; + [[nodiscard]] std::vector ChildrenOf(PictID pid) const; + [[nodiscard]] std::optional ParentIndex(PictID parent, PictID child) const; + + [[nodiscard]] std::vector> EdgeList() const; + + [[nodiscard]] std::vector ExecuteOrder() const; + + // Note: use only for Serialization! + bool LoadParent(PictID child, PictID parent); + +private: + void AddItem(PictID item, const std::vector& connectedItems); + void Erase(PictID item); + + size_t InsertKeyValue(PictID item); + [[nodiscard]] size_t Item2ID(PictID item); + [[nodiscard]] std::vector Item2ID(const std::vector& input); + [[nodiscard]] std::optional FindItemIndex(PictID item) const; + [[nodiscard]] std::vector Index2PIDs(const std::vector& input) const; +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/ossGridFacet.h b/ccl/core/include/ccl/oss/ossGridFacet.h new file mode 100644 index 0000000..311f7e6 --- /dev/null +++ b/ccl/core/include/ccl/oss/ossGridFacet.h @@ -0,0 +1,83 @@ +#pragma once + +#include "ccl/oss/Pict.hpp" +#include "ccl/cclMeta.hpp" + +namespace ccl::oss { + +class OSSchema; + +using GridIndex = int32_t; // TODO: change to int16_t after serialization fix + +//! Decartian grid position +struct GridPosition { + GridIndex row{ 0 }; + GridIndex column{ 0 }; + + constexpr GridPosition() = default; + + constexpr GridPosition(GridIndex row, GridIndex column) noexcept + : row{ row }, column{ column } {} + + bool operator==(const GridPosition& other) const noexcept { + return row == other.row && column == other.column; + } + bool operator!=(const GridPosition& other) const noexcept { + return row != other.row || column != other.column; + } + + [[nodiscard]] constexpr double EffectiveColumn() const { + return column + row / 2.0; // NOLINT(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + } +}; + +} // namespace ccl::oss + +namespace std { + template <> + struct hash { + uint32_t operator()(const ccl::oss::GridPosition& k) const noexcept { + using std::hash; + return static_cast(hash()(k.row) ^ (hash()(k.column) << 1U)); + } + }; +} // namespace std + +namespace ccl::oss { + +using Grid = std::unordered_map; + +//! OSS grid positions facet +class ossGridFacet final : public meta::MutatorFacet { + friend class OSSchema; + + Grid grid{}; + +public: + static constexpr GridPosition origin{ 0, 0 }; + +public: + explicit ossGridFacet(OSSchema& oss) noexcept // NOLINT(bugprone-exception-escape) + : MutatorFacet(oss) {} + +public: + [[nodiscard]] const Grid& data() const noexcept; + + [[nodiscard]] std::optional operator()(GridPosition pos) const; + [[nodiscard]] std::optional operator()(PictID pid) const; + + [[nodiscard]] GridIndex MaxColumnIn(GridIndex row) const; + [[nodiscard]] GridIndex CountRows() const; + + bool ShiftPict(PictID pid, int32_t shift); + void LoadPosition(PictID pid, GridPosition pos); + +private: + [[nodiscard]] GridPosition ChildPosFor(PictID parent1, PictID parent2) const; + [[nodiscard]] GridPosition ClosestFreePos(GridPosition start = origin) const; + + void SetPosFor(PictID pid, GridPosition pos); + void Erase(PictID pid); +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/ossOperationsFacet.h b/ccl/core/include/ccl/oss/ossOperationsFacet.h new file mode 100644 index 0000000..e8a59bb --- /dev/null +++ b/ccl/core/include/ccl/oss/ossOperationsFacet.h @@ -0,0 +1,87 @@ +#pragma once + +#include "ccl/oss/OperationProcessor.hpp" + +#include "ccl/oss/Pict.hpp" +#include "ccl/Source.hpp" +#include "ccl/cclMeta.hpp" + +namespace ccl::oss { + +class ossSourceFacet; +class OSSchema; + +//! OSS operation handle +struct OperationHandle final { + ops::Type type{ ops::Type::tba }; + meta::UniqueCPPtr options{ nullptr }; + meta::UniqueCPPtr translations{ nullptr }; + + bool broken{ false }; + bool outdated{ false }; + + void Reset() noexcept; + void InitOperation(ops::Type operation, + meta::UniqueCPPtr newOptions) noexcept; +}; + +//! OSS operations facet +class ossOperationsFacet final : public meta::MutatorFacet { + friend class OSSchema; + +public: + std::string ossPath{}; + +private: + using Operations = std::unordered_map>; + using Processors = std::vector>; + using ProcessorMapping = std::unordered_map; + + Operations operations{}; + Processors procs; + ProcessorMapping opProcs; + +public: + explicit ossOperationsFacet(OSSchema& oss); + +public: + [[nodiscard]] const OperationHandle* operator()(PictID pid) const; + [[nodiscard]] ops::Status StatusOf(PictID pid) const; + [[nodiscard]] bool HasOperation(PictID pid) const { return operator()(pid) != nullptr; } + + [[nodiscard]] std::unordered_set VariantsFor(PictID pid) const; + [[nodiscard]] bool IsExecutable(PictID pid); + [[nodiscard]] bool IsTranslatable(PictID pid); + + bool InitFor(PictID pid, ops::Type operation, + std::unique_ptr newOptions = nullptr); + bool Execute(PictID pid, bool autoDiscard = false); + void ExecuteAll(); + + [[nodiscard]] change::Usage QueryEntityUsage(const src::Source& src, EntityUID cstID) const; + +private: + OperationHandle* Access(PictID pid); + [[nodiscard]] bool IsOperable(PictID pid) const; + [[nodiscard]] bool CheckTranslations(PictID pid); + void Erase(PictID pid) noexcept; + bool CheckOperation(PictID pid); + + [[nodiscard]] ops::Signature SignaFor(PictID pid) const; + [[nodiscard]] ops::Call CallFor(PictID pid) const; + + bool RunOperation(PictID pid, bool autoDiscard); + bool PrepareParents(PictID pid); + [[nodiscard]] ops::Result CreateNewResult(PictID pid); + [[nodiscard]] std::optional AggregateVersions(PictID pid, ops::Result& opResult) const; + + bool SaveOperationResult(PictID pid, const EntityTranslation& old2New, ops::Result&& opResult); + + [[nodiscard]] change::Usage CstUsage(EntityUID cstID, PictID pid) const; + + void UpdateChild(PictID child, size_t childIndex, const EntityTranslation& oldToNew); + void UpdateTranslations(PictID child, size_t childIndex, const EntityTranslation& oldToNew); + void UpdateOptions(PictID child, size_t childIndex, const EntityTranslation& oldToNew); +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/oss/ossSourceFacet.h b/ccl/core/include/ccl/oss/ossSourceFacet.h new file mode 100644 index 0000000..2be4e07 --- /dev/null +++ b/ccl/core/include/ccl/oss/ossSourceFacet.h @@ -0,0 +1,79 @@ +#pragma once + +#include "ccl/oss/Pict.hpp" +#include "ccl/Source.hpp" +#include "ccl/cclMeta.hpp" + +namespace ccl::oss { + +class OSSchema; +class ossOperationsFacet; + +//! OSS source management facet +class ossSourceFacet final : public meta::MutatorFacet { + friend class OSSchema; + friend class ossOperationsFacet; + +public: + std::u8string ossDomain{}; + +private: + using Container = std::unordered_map; + Container sources{}; + bool disableImport{ false }; + + static constexpr bool loadData = true; + +public: + ~ossSourceFacet() noexcept; + ossSourceFacet(const ossSourceFacet&) = delete; + ossSourceFacet& operator=(const ossSourceFacet&) = delete; + + explicit ossSourceFacet(OSSchema& oss); + +public: + [[nodiscard]] const src::Handle* operator()(PictID pid) const; + [[nodiscard]] bool IsConnectedWith(const src::Source& src) const; + [[nodiscard]] bool IsAssociatedWith(const src::Descriptor& localDesc) const; + [[nodiscard]] std::optional Src2PID(const src::Source& src) const; + + [[nodiscard]] src::Source* OpenSrc(PictID pid); + [[nodiscard]] src::Source* ActiveSrc(PictID pid); + + bool Rename(PictID pid, const std::u8string& newLocalName); + void Discard(PictID pid); + + bool ConnectPict2Src(PictID pid, src::Source& src); + bool ConnectSrc2Pict(PictID pid, src::Source& src); + + [[nodiscard]] const src::DataStream* DataFor(PictID pid); + + void ReconnectAll(); + +private: + void Erase(PictID pid); + void CloseAll() noexcept; + + bool UpdateSync(PictID pid); + bool InputData(PictID pid, meta::UniqueCPPtr data); + + bool Import(src::Source& src); + void UpdateOnSrcChange(PictID pid); + void Disconnect(src::Source& src); + + bool ForceConnection(PictID pid, src::Source& src, bool importFromSrc); + void ConnectInternal(PictID pid, src::Source& src, bool importFromSrc); + void SyncPict(PictID pid, bool importFromSrc); + void UpdateHashes(PictID pid); + + void SyncData(PictID pid, src::Handle& handle, bool importFromSrc); + + static void EnableTracking(src::DataStream& data); + [[nodiscard]] static std::optional + ReadAttribute(src::DataStream::Attribute attr, const src::DataStream& data) noexcept; + static bool WriteAttribute(const src::DataStream::AttrValue& val, src::DataStream& data); + + [[nodiscard]] src::Descriptor GlobalDesc(const src::Descriptor& local) const; +}; + +} // namespace ccl::oss \ No newline at end of file diff --git a/ccl/core/include/ccl/semantic/ConceptRecord.h b/ccl/core/include/ccl/semantic/ConceptRecord.h new file mode 100644 index 0000000..7d5a377 --- /dev/null +++ b/ccl/core/include/ccl/semantic/ConceptRecord.h @@ -0,0 +1,31 @@ +#pragma once + +#include "ccl/semantic/RSConcept.h" +#include "ccl/semantic/TextConcept.h" + +namespace ccl::semantic { + +//! Constituent of RSCore +class ConceptRecord { +public: + EntityUID uid{}; + std::string alias{}; + + CstType type{ CstType::base }; + + std::string rs{}; + std::string convention{}; + + lang::LexicalTerm term{}; + lang::ManagedText definition{}; + +public: + explicit ConceptRecord() = default; + explicit ConceptRecord(const RSConcept& rsPart, const TextConcept& textPart); + +public: + RSConcept SpawnRS() const; + TextConcept SpawnText() const; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/CstFilters.hpp b/ccl/core/include/ccl/semantic/CstFilters.hpp new file mode 100644 index 0000000..da21cad --- /dev/null +++ b/ccl/core/include/ccl/semantic/CstFilters.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "ccl/semantic/RSCore.h" +#include "ccl/rslang/Typification.h" + +namespace ccl::semantic { + +template +inline VectorOfEntities FilterCst(const RSCore& core, Filter filter) { + VectorOfEntities result{}; + for (const auto uid : core.List()) { + if (filter(uid)) { + result.push_back(uid); + } + } + return result; +} + +inline VectorOfEntities FilterCst(const RSCore& core, CstType type) { + const auto filter = [&core, &type](const EntityUID uid) { + return core.GetRS(uid).type == type; + }; + return FilterCst(core, filter); +} + +inline VectorOfEntities FilterCst(const RSCore& core, const rslang::ExpressionType& type) { + const auto filter = [&core, &type](const EntityUID uid) { + const auto& cstType = core.GetParse(uid).exprType; + return cstType.has_value() && type == cstType.value(); + }; + return FilterCst(core, filter); +} + +inline VectorOfEntities FilterCst(const RSCore& core, const std::string& txt) { + const auto filter = [&core, &txt](const EntityUID uid) { + return core.GetRS(uid).MatchStr(txt) || core.GetText(uid).MatchStr(txt); + }; + return FilterCst(core, filter); +} + +inline VectorOfEntities FilterEmpty(const RSCore& core) { + const auto filter = [&core](const EntityUID uid) { + return core.GetRS(uid).IsEmpty() && core.GetText(uid).IsEmpty() ? uid : std::optional{}; + }; + return FilterCst(core, filter); +} + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/CstList.h b/ccl/core/include/ccl/semantic/CstList.h new file mode 100644 index 0000000..0d5e194 --- /dev/null +++ b/ccl/core/include/ccl/semantic/CstList.h @@ -0,0 +1,83 @@ +#pragma once + +#include + +#include "ccl/Entity.hpp" +#include "ccl/semantic//CstType.hpp" + +namespace ccl::semantic { + +class ListIterator; + +//! Constituents ordering facet for RSCore +class CstList { + friend class ListIterator; + +public: + using TypeSource = std::function; + +private: + using Container = std::list; + Container order{}; + TypeSource types; + +public: + explicit CstList(TypeSource types) + : types{ std::move(types) } {} + + CstList(const CstList& rhs); + CstList& operator=(const CstList& rhs); + CstList(CstList&& rhs) noexcept; + CstList& operator=(CstList&& rhs) noexcept; + +public: + using value_type = Container::value_type; + using size_type = Container::size_type; + + [[nodiscard]] ListIterator begin() const noexcept; + [[nodiscard]] ListIterator end() const noexcept; + [[nodiscard]] size_type size() const noexcept; + [[nodiscard]] bool empty() const noexcept { return size() == 0; } + + [[nodiscard]] ListIterator Find(EntityUID entity) const; + + void Insert(EntityUID newID); + void Erase(EntityUID target); + bool MoveBefore(EntityUID what, ListIterator iWhere); + + [[nodiscard]] VectorOfEntities SortSubset(const SetOfEntities& subset) const; + +private: + [[nodiscard]] ListIterator InsertPositionFor(CstType insertType) const; + [[nodiscard]] bool CanMoveBefore(ListIterator what, ListIterator iWhere) const; +}; + +//! Constituents list iterator +class ListIterator { + friend class CstList; + using Container = CstList::Container; + + const CstList* container{ nullptr }; + Container::const_iterator it{}; + +private: + explicit ListIterator(const CstList* container, Container::const_iterator iter) noexcept; + +public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = EntityUID; + using difference_type = std::ptrdiff_t; + using pointer = const EntityUID*; + using reference = const EntityUID&; + + [[nodiscard]] bool operator==(const ListIterator& iter2) const noexcept; + [[nodiscard]] bool operator!=(const ListIterator& iter2) const noexcept { return !(*this == iter2); } + + ListIterator& operator++() noexcept; + ListIterator& operator--() noexcept; + + [[nodiscard]] pointer operator->() const noexcept; + [[nodiscard]] reference operator*() const noexcept; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/CstType.hpp b/ccl/core/include/ccl/semantic/CstType.hpp new file mode 100644 index 0000000..28caff3 --- /dev/null +++ b/ccl/core/include/ccl/semantic/CstType.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include "ccl/cclMeta.hpp" + +namespace ccl::semantic { + +//! Consituent type enumeration +enum class CstType : uint8_t { + base = 1, // Базисное множество (БМ) + constant = 2, // Константное множество (КМ) + structured = 4, // Род структуры + axiom = 5, // Аксиома + term = 6, // Терм + function = 7, // Терм-функция + theorem = 8, // Теорема + predicate = 9, // Предикат + size_ +}; + +[[nodiscard]] constexpr bool IsBasic(CstType type) noexcept; + +[[nodiscard]] constexpr bool IsBaseSet(CstType type) noexcept; +[[nodiscard]] constexpr bool IsBaseNotion(CstType type) noexcept; + +[[nodiscard]] constexpr bool IsCalculable(CstType type) noexcept; + +[[nodiscard]] constexpr bool IsStatement(CstType type) noexcept; +[[nodiscard]] constexpr bool IsRSObject(CstType type) noexcept; +[[nodiscard]] constexpr bool IsCallable(CstType type) noexcept; + +using CstTypeIter = meta::EnumIter +< + CstType, + CstType::base, CstType::constant, CstType::structured, + CstType::axiom, CstType::term, CstType::function, CstType::theorem, CstType::predicate +>; + +constexpr bool IsBasic(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::base: + case CstType::constant: + case CstType::structured: + return true; + } +} + +constexpr bool IsRSObject(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::base: + case CstType::constant: + case CstType::structured: + case CstType::term: + return true; + } +} + +constexpr bool IsBaseSet(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::base: + case CstType::constant: + return true; + } +} + +constexpr bool IsBaseNotion(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::base: + case CstType::constant: + case CstType::structured: + return true; + } +} + +constexpr bool IsCalculable(const CstType type) noexcept { + return !IsBaseNotion(type) && !IsCallable(type); +} + +constexpr bool IsCallable(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::function: + case CstType::predicate: + return true; + } +} + +constexpr bool IsStatement(const CstType type) noexcept { + switch (type) { + default: return false; + case CstType::axiom: + case CstType::theorem: + return true; + } +} + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/IdentityManager.h b/ccl/core/include/ccl/semantic/IdentityManager.h new file mode 100644 index 0000000..d6e85e1 --- /dev/null +++ b/ccl/core/include/ccl/semantic/IdentityManager.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ccl/tools/EntityGenerator.h" +#include "ccl/tools/CstNameGenerator.h" +#include "ccl/Substitutes.hpp" + +namespace ccl::semantic { + +//! Concept identifier pair in RSCore +struct ConceptID { + EntityUID uid{}; + std::string alias{}; + + [[nodiscard]] constexpr bool operator==(const ConceptID& rhs) const { + return uid == rhs.uid && alias == rhs.alias; + } + [[nodiscard]] constexpr bool operator!=(const ConceptID& rhs) const { + return !operator==(rhs); + } +}; + +//! Constituent identification facet of RSCore +class IdentityManager { +private: + tools::EntityGenerator idGenerator{}; + tools::CstNameGenerator aliasGenerator{}; + +public: + [[nodiscard]] ConceptID GenerateNewID(CstType type); + [[nodiscard]] ConceptID RegisterID(EntityUID uid, const std::string& name, CstType type); + [[nodiscard]] ConceptID RegisterEntity(EntityUID uid, CstType type); + + bool TryAlias(const std::string& oldValue, const std::string& newValue, CstType type); + void Erase(EntityUID target, const std::string& name) noexcept; + void Clear() noexcept; + +private: + [[nodiscard]] bool NeedNameChangeFor(const std::string& name, CstType type) const; + +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/InterpretationStorage.h b/ccl/core/include/ccl/semantic/InterpretationStorage.h new file mode 100644 index 0000000..27a58fa --- /dev/null +++ b/ccl/core/include/ccl/semantic/InterpretationStorage.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ccl/semantic/TextData.hpp" +#include "ccl/rslang/StructuredData.h" +#include "ccl/Entity.hpp" + +namespace ccl::semantic { + +//! Entity interpretation manager +class InterpretationStorage { + using TextContainer = std::unordered_map; + using InterpContainer = std::unordered_map; + + TextContainer textData{}; + InterpContainer rsData{}; + +public: + void Clear() noexcept; + void Erase(EntityUID target) noexcept; + + [[nodiscard]] const TextInterpretation* GetTextInterpretationFor(EntityUID uid) const; + int32_t AddInterpretantFor(EntityUID uid, const std::string& name); + void SetTextInterpretationFor(EntityUID uid, const TextInterpretation& newInterp); + + [[nodiscard]] std::optional GetRSIFor(EntityUID uid) const; + void SetRSInterpretationFor(EntityUID uid, object::StructuredData val); +}; + +} // namespace ccl::semantic \ No newline at end of file diff --git a/ccl/core/include/ccl/semantic/RSConcept.h b/ccl/core/include/ccl/semantic/RSConcept.h new file mode 100644 index 0000000..f51bdf3 --- /dev/null +++ b/ccl/core/include/ccl/semantic/RSConcept.h @@ -0,0 +1,35 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/semantic/CstType.hpp" +#include "ccl/rslang/RSExpr.h" + +namespace ccl::semantic { + +//! RS form of a concept +struct RSConcept { + EntityUID uid{}; + std::string alias{}; + + CstType type{ CstType::base }; + + std::string definition{}; + std::string convention{}; + + explicit RSConcept(const EntityUID entity, std::string alias, const CstType type = CstType::base, + std::string definition = {}, std::string convention = {}) noexcept + : uid{ entity }, alias{ std::move(alias) }, type{ type }, + definition{ std::move(definition) }, convention{ std::move(convention) } {} + + RSConcept() = default; + + [[nodiscard]] bool operator==(const RSConcept& rhs) const noexcept; + [[nodiscard]] bool operator!=(const RSConcept& rhs) const noexcept { return !(*this == rhs); } + + [[nodiscard]] bool IsEmpty() const noexcept; + [[nodiscard]] bool MatchStr(const std::string& searchStr) const; + + void Translate(const StrTranslator& old2New); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/RSCore.h b/ccl/core/include/ccl/semantic/RSCore.h new file mode 100644 index 0000000..126cd7e --- /dev/null +++ b/ccl/core/include/ccl/semantic/RSCore.h @@ -0,0 +1,101 @@ +#pragma once + +#include "ccl/cclMeta.hpp" + +#include "ccl/semantic/ConceptRecord.h" +#include "ccl/semantic/Schema.h" +#include "ccl/semantic/Thesaurus.h" +#include "ccl/semantic/CstList.h" +#include "ccl/semantic/IdentityManager.h" + +namespace ccl::semantic { + +class RSFormIterator; + +//! Core of system of concepts +class RSCore { + friend class RSFormIterator; + +private: + IdentityManager identifiers{}; + Thesaurus thesaurus{}; + Schema schema{}; + CstList cstList{ [&core = *this] (const EntityUID uid) { return core.RSLang().At(uid).type; } }; + +public: + [[nodiscard]] RSFormIterator begin() const noexcept; + [[nodiscard]] RSFormIterator end() const noexcept; + [[nodiscard]] size_t size() const noexcept; + [[nodiscard]] bool empty() const noexcept { return size() == 0; } + + [[nodiscard]] bool Contains(EntityUID entity) const; + [[nodiscard]] std::optional FindAlias(const std::string& name) const; + + [[nodiscard]] const CstList& List() const noexcept; + [[nodiscard]] const Thesaurus& Texts() const noexcept; + [[nodiscard]] const Schema& RSLang() const noexcept; + + //! requires Contains(entity) == true + [[nodiscard]] const RSConcept& GetRS(EntityUID entity) const; + [[nodiscard]] const TextConcept& GetText(EntityUID entity) const; + [[nodiscard]] const ParsingInfo& GetParse(EntityUID entity) const; + [[nodiscard]] ConceptRecord AsRecord(EntityUID entity) const; + + EntityUID Emplace(CstType type, const std::string& definition = {}); + EntityUID Insert(ConceptRecord&& cst); + EntityUID InsertCopy(EntityUID target, const RSCore& source); + EntityUID InsertCopy(const ConceptRecord& cst); + VectorOfEntities InsertCopy(const VectorOfEntities& input, const RSCore& source); + VectorOfEntities InsertCopy(const std::vector& input); + + bool MoveBefore(EntityUID what, ListIterator iWhere); + + bool Erase(EntityUID target); + + bool SetAliasFor(EntityUID target, const std::string& newValue, bool substitueMentions = true); + bool SetExpressionFor(EntityUID target, const std::string& expression); + bool SetConventionFor(EntityUID target, const std::string& convention); + + bool SetTermFor(EntityUID target, const std::string& termRef); + bool SetTermFormFor(EntityUID target, const std::string& termRef, const lang::Morphology& form); + bool SetDefinitionFor(EntityUID target, const std::string& textDef); + + void Translate(EntityUID target, const StrTranslator& old2New); + void TranslateAll(const StrTranslator& old2New); + + void TranslateTexts(EntityUID target, const StrTranslator& old2New); + void TranslateDef(EntityUID target, const StrTranslator& old2New); + void TranslateTerm(EntityUID target, const StrTranslator& old2New); + + void ResetAliases(); + + EntityUID Load(ConceptRecord&& cst); + void UpdateState(); +}; + +//! RS iterator +class RSFormIterator { + friend class RSCore; + + RSIterator iter; + +private: + explicit RSFormIterator(RSIterator iter) noexcept; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = EntityUID; + using difference_type = std::ptrdiff_t; + using pointer = const EntityUID*; + using reference = const EntityUID&; + + [[nodiscard]] bool operator==(const RSFormIterator& iter2) const noexcept; + [[nodiscard]] bool operator!=(const RSFormIterator& iter2) const noexcept { return !(*this == iter2); } + + RSFormIterator& operator++() noexcept; + + [[nodiscard]] pointer operator->() const noexcept; + [[nodiscard]] reference operator*() const noexcept; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/RSForm.h b/ccl/core/include/ccl/semantic/RSForm.h new file mode 100644 index 0000000..4e2ce5c --- /dev/null +++ b/ccl/core/include/ccl/semantic/RSForm.h @@ -0,0 +1,95 @@ +#pragma once + +#include "ccl/Source.hpp" +#include "ccl/cclChange.hpp" + +#include "ccl/semantic/RSCore.h" +#include "ccl/semantic/rsModificationFacet.h" +#include "ccl/semantic/rsOperationFacet.h" + +namespace ccl::ops { class RSAggregator; } // namespace ccl::ops + +namespace ccl::semantic { + +//! RSForm of system of concepts +class RSForm : public src::DataStream, public change::ObservableMods { + friend class ops::RSEquationProcessor; + friend class ops::RSAggregator; + + friend class rsOperationFacet; + friend class rsModificationFacet; + +public: + std::string title{}; + std::string alias{}; + std::string comment{}; + +private: + RSCore core{}; + std::unique_ptr mods{ std::make_unique(*this) }; + std::unique_ptr operations{ std::make_unique(*this) }; + +public: + ~RSForm() noexcept override = default; + RSForm() = default; + RSForm(const RSForm& rhs); + RSForm& operator=(const RSForm& rhs); + +public: + [[nodiscard]] src::DataType Type() const noexcept override { return src::DataType::rsSchema; } + + [[nodiscard]] const RSCore& Core() const noexcept; + [[nodiscard]] const CstList& List() const noexcept; + [[nodiscard]] const Thesaurus& Texts() const noexcept; + [[nodiscard]] const Schema& RSLang() const noexcept; + + [[nodiscard]] rsModificationFacet& Mods() noexcept; + [[nodiscard]] const rsModificationFacet& Mods() const noexcept; + [[nodiscard]] rsOperationFacet& Ops() noexcept; + [[nodiscard]] const rsOperationFacet& Ops() const noexcept; + + [[nodiscard]] bool Contains(EntityUID entity) const; + [[nodiscard]] const RSConcept& GetRS(EntityUID entity) const; + [[nodiscard]] const TextConcept& GetText(EntityUID entity) const; + [[nodiscard]] const ParsingInfo& GetParse(EntityUID entity) const; + + EntityUID Emplace(CstType type, const std::string& definition = {}); + EntityUID InsertCopy(EntityUID target, const RSCore& source); + EntityUID InsertCopy(const ConceptRecord& cst); + VectorOfEntities InsertCopy(const VectorOfEntities& input, const RSCore& source); + VectorOfEntities InsertCopy(const std::vector& input); + + bool MoveBefore(EntityUID what, ListIterator iWhere); + + bool Erase(EntityUID target); + + bool SetAliasFor(EntityUID target, const std::string& newValue, bool substitue = true); + bool SetExpressionFor(EntityUID target, const std::string& expression); + bool SetTermFor(EntityUID target, const std::string& termRef); + bool SetTermFormFor(EntityUID target, const std::string& termRef, const lang::Morphology& form); + bool SetDefinitionFor(EntityUID target, const std::string& textDef); + bool SetConventionFor(EntityUID target, const std::string& convention); + + void ResetAliases(); + + EntityUID Load(ConceptRecord&& cst); + void UpdateState(); + [[nodiscard]] RSCore& LoadCore() noexcept { return core; } + + // Note: hashes ignore ordering + [[nodiscard]] change::Hash CoreHash() const; + [[nodiscard]] change::Hash FullHash() const; + +private: + [[nodiscard]] inline bool NotifyAndReturn(const bool result) { + if (result) { + NotifyModification(); + } + return result; + } + [[nodiscard]] bool EraseInternal(EntityUID target); + EntityTranslation DeleteDuplicatesInternal(); + void EquateTextsOf(EntityUID delID, EntityUID hierID, const ops::Equation& params); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/RSModel.h b/ccl/core/include/ccl/semantic/RSModel.h new file mode 100644 index 0000000..dadb098 --- /dev/null +++ b/ccl/core/include/ccl/semantic/RSModel.h @@ -0,0 +1,84 @@ +#pragma once + +#include "ccl/semantic/RSCore.h" + +#include "ccl/semantic/rsValuesFacet.h" +#include "ccl/semantic/rsCalculationFacet.h" +#include "ccl/cclChange.hpp" + +namespace ccl::semantic { + +//! RSModel - data interpretation of RSForm system of concepts +class RSModel : public change::ObservableMods { + friend class rsValuesFacet; + friend class rsCalculationFacet; + +public: + std::string title{}; + std::string alias{}; + std::string comment{}; + +private: + RSCore core{}; + std::unique_ptr dataFacet{ std::make_unique(*this) }; + std::unique_ptr calulatorFacet{ std::make_unique(*this) }; + +public: + ~RSModel() noexcept = default; + RSModel() = default; + RSModel(const RSModel&) = delete; + RSModel& operator=(const RSModel&) = delete; + +public: + [[nodiscard]] const RSCore& Core() const noexcept; + [[nodiscard]] const CstList& List() const noexcept; + [[nodiscard]] const Thesaurus& Texts() const noexcept; + [[nodiscard]] const Schema& RSLang() const noexcept; + + [[nodiscard]] rsValuesFacet& Values() noexcept; + [[nodiscard]] const rsValuesFacet& Values() const noexcept; + [[nodiscard]] rsCalculationFacet& Calculations() noexcept; + [[nodiscard]] const rsCalculationFacet& Calculations() const noexcept; + + [[nodiscard]] bool Contains(EntityUID entity) const; + [[nodiscard]] const RSConcept& GetRS(EntityUID entity) const; + [[nodiscard]] const TextConcept& GetText(EntityUID entity) const; + [[nodiscard]] const ParsingInfo& GetParse(EntityUID entity) const; + + EntityUID Emplace(CstType type, const std::string& definition = {}); + EntityUID InsertCopy(EntityUID target, const RSCore& source); + EntityUID InsertCopy(const ConceptRecord& cst); + VectorOfEntities InsertCopy(const VectorOfEntities& input, const RSCore& source); + VectorOfEntities InsertCopy(const std::vector& input); + + bool MoveBefore(EntityUID what, ListIterator iWhere); + + bool Erase(EntityUID target); + + bool SetAliasFor(EntityUID target, const std::string& newName, bool substitue = true); + bool SetExpressionFor(EntityUID target, const std::string& expression); + bool SetTermFor(EntityUID target, const std::string& termRef); + bool SetTermFormFor(EntityUID target, const std::string& termRef, const lang::Morphology& form); + bool SetDefinitionFor(EntityUID target, const std::string& textDef); + bool SetConventionFor(EntityUID target, const std::string& convention); + + void ResetAliases(); + + // Note: use only for creating from empty state + EntityUID Load(ConceptRecord&& cst); + [[nodiscard]] RSCore& LoadCore() noexcept { return core; } + void FinalizeLoadingCore(); + void UpdateState(); + +private: + [[nodiscard]] inline bool NotifyAndReturn(const bool result) { + if (result) { + NotifyModification(); + } + return result; + } + void AfterInsert(EntityUID target); + void ResetDependants(EntityUID target); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/Schema.h b/ccl/core/include/ccl/semantic/Schema.h new file mode 100644 index 0000000..cea9e41 --- /dev/null +++ b/ccl/core/include/ccl/semantic/Schema.h @@ -0,0 +1,143 @@ +#pragma once + +#include "ccl/rslang/Auditor.h" +#include "ccl/rslang/SyntaxTree.h" +#include "ccl/semantic/RSConcept.h" +#include "ccl/graph/CGraph.h" + +#include + +namespace ccl::semantic { + +class RSIterator; + +//! Parsing status enumeration +enum class ParsingStatus : int8_t { + UNKNOWN = 0, + VERIFIED, + INCORRECT, +}; + +struct ParsingInfo { + ParsingStatus status{ ParsingStatus::UNKNOWN }; + meta::UniqueCPPtr ast{}; + std::optional exprType{}; + std::optional arguments{}; + rslang::ValueClass valueClass{ rslang::ValueClass::invalid }; + + ~ParsingInfo() noexcept = default; + ParsingInfo() noexcept = default; + + ParsingInfo(const ParsingInfo& info2); + ParsingInfo& operator=(const ParsingInfo& info2); + ParsingInfo(ParsingInfo&& info2) noexcept; + ParsingInfo& operator=(ParsingInfo&& info2) noexcept; + + [[nodiscard]] const rslang::ExpressionType* TypePtr() const; + [[nodiscard]] const rslang::Typification* Typification() const; + void Reset() noexcept; +}; + +//! RS schema for system of concepts +class Schema final : public rslang::TypeContext { + friend class RSIterator; + + // Note: using map for consistent iteration order + using Storage = std::map; + Storage storage{}; + + std::unordered_map info{}; + mutable graph::UpdatableGraph graph; + + // Note: Auditor should be created last because it needs context references + using RSAuditor = std::unique_ptr; + mutable RSAuditor auditor{ std::make_unique(*this, VCContext(), ASTContext()) }; + +public: + ~Schema() noexcept final = default; + explicit Schema(); + + Schema(const Schema& rhs); + Schema& operator=(const Schema& rhs); + Schema(Schema&& rhs) noexcept; + Schema& operator=(Schema&& rhs) noexcept; + +public: + [[nodiscard]] RSIterator begin() const noexcept; + [[nodiscard]] RSIterator end() const noexcept; + [[nodiscard]] size_t size() const noexcept; + [[nodiscard]] bool empty() const noexcept { return size() == 0; } + + [[nodiscard]] size_t Count(CstType type) const; + [[nodiscard]] bool Contains(EntityUID entity) const; + [[nodiscard]] const RSConcept& At(EntityUID entity) const; + [[nodiscard]] const ParsingInfo& InfoFor(EntityUID entity) const; + + [[nodiscard]] std::optional FindAlias(const std::string& alias) const; + [[nodiscard]] std::optional FindExpr(const std::string& expr) const; + + [[nodiscard]] const graph::CGraph& Graph() const; + + [[nodiscard]] const rslang::ExpressionType* TypeFor(const std::string& globalName) const final; + [[nodiscard]] const rslang::FunctionArguments* FunctionArgsFor(const std::string& globalName) const final; + [[nodiscard]] std::optional TraitsFor(const rslang::Typification& type) const final; + + [[nodiscard]] rslang::SyntaxTreeContext ASTContext() const; + [[nodiscard]] rslang::ValueClassContext VCContext() const; + + bool Emplace(EntityUID newID, std::string newAlias, CstType type, + std::string definition = {}, std::string convention = {}); + bool InsertCopy(const RSConcept& cst); + bool Insert(RSConcept&& cst); + void Load(RSConcept&& cst); + void Erase(EntityUID target); + + bool SetAliasFor(EntityUID target, const std::string& newValue, bool substitueMentions = true); + bool SetTypeFor(EntityUID target, CstType newValue); + bool SetDefinitionFor(EntityUID target, const std::string& expression); + bool SetConventionFor(EntityUID target, const std::string& convention); + + void SubstitueAliases(const StrTranslator& old2New); + void Translate(EntityUID target, const StrTranslator& old2New); + void TranslateAll(const StrTranslator& old2New); + + [[nodiscard]] static bool CheckTypeConstistency(const rslang::ExpressionType& type, CstType cstType) noexcept; + [[nodiscard]] std::optional Evaluate(const std::string& input) const; + + [[nodiscard]] std::unique_ptr MakeAuditor() const; + + void UpdateState(); + +private: + void ResetInfo() noexcept; + void TriggerParse(EntityUID target); + void ParseCst(EntityUID target); + void SaveInfoTo(ParsingInfo& out); +}; + +//! RS concept iterator +class RSIterator { + friend class Schema; + using Container = Schema::Storage; + Container::const_iterator iterator; + +private: + explicit RSIterator(Container::const_iterator iter) noexcept; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = RSConcept; + using difference_type = std::ptrdiff_t; + using pointer = const RSConcept*; + using reference = const RSConcept&; + + [[nodiscard]] bool operator==(const RSIterator& iter2) const noexcept; + [[nodiscard]] bool operator!=(const RSIterator& iter2) const noexcept { return !(*this == iter2); } + + RSIterator& operator++() noexcept; + + [[nodiscard]] pointer operator->() const noexcept; + [[nodiscard]] reference operator*() const noexcept; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/TextConcept.h b/ccl/core/include/ccl/semantic/TextConcept.h new file mode 100644 index 0000000..ee4b029 --- /dev/null +++ b/ccl/core/include/ccl/semantic/TextConcept.h @@ -0,0 +1,35 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/Substitutes.hpp" +#include "ccl/lang/LexicalTerm.h" + +namespace ccl::semantic { + +//! Text form of a concept +class TextConcept { +public: + EntityUID uid{}; + std::string alias{}; + + lang::LexicalTerm term{}; + lang::ManagedText definition{}; + +public: + explicit TextConcept() noexcept = default; + explicit TextConcept(const EntityUID entity, std::string alias, + lang::LexicalTerm term = {}, lang::ManagedText definition = {}) noexcept + : uid{ entity }, alias{ std::move(alias) }, term{ std::move(term) }, definition{ std::move(definition) } {} + +public: + [[nodiscard]] bool operator==(const TextConcept& rhs) const noexcept; + [[nodiscard]] bool operator!=(const TextConcept& rhs) const noexcept { return !(*this == rhs); } + + [[nodiscard]] bool IsEmpty() const noexcept; + [[nodiscard]] bool MatchStr(const std::string& searchStr) const; + + void Translate(const StrTranslator& old2New, const lang::EntityTermContext& cntxt); + void TranslateRaw(const StrTranslator& old2New); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/TextData.hpp b/ccl/core/include/ccl/semantic/TextData.hpp new file mode 100644 index 0000000..128eb09 --- /dev/null +++ b/ccl/core/include/ccl/semantic/TextData.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace ccl::semantic { + +//! Text interpretation +class TextInterpretation { + using Container = std::map; + Container interpretants{}; + +public: + using CIter = typename Container::const_iterator; + using size_type = typename Container::size_type; + using value_type = typename Container::value_type; + using mapped_type = typename Container::mapped_type; + using key_type = typename Container::key_type; + + TextInterpretation() = default; + explicit TextInterpretation(const std::vector& interpr) { + for (const auto& it : interpr) { + PushBack(it); + } + } + explicit TextInterpretation(std::initializer_list init) { + for (const auto& [key, value] : init) { + SetInterpretantFor(key, value); + } + } + +public: + void Clear() noexcept { + interpretants.clear(); + } + [[nodiscard]] bool empty() const noexcept { + return std::empty(interpretants); + } + [[nodiscard]] size_type size() const noexcept { + return std::size(interpretants); + } + [[nodiscard]] CIter begin() const noexcept { + return std::begin(interpretants); + } + [[nodiscard]] CIter end() const noexcept { + return std::end(interpretants); + } + + [[nodiscard]] bool HasInterpretantFor(const int32_t id) const { + return interpretants.contains(id); + } + [[nodiscard]] const std::string& GetInterpretantFor(const int32_t id) const { + return interpretants.at(id); + } + void SetInterpretantFor(const int32_t id, const std::string& val) { + interpretants[id] = val; + } + void EraseInterpretee(const int32_t& id) { + interpretants.erase(id); + } + + [[nodiscard]] bool operator==(const TextInterpretation& rhs) const { + return interpretants == rhs.interpretants; + } + [[nodiscard]] bool operator!=(const TextInterpretation& rhs) const { + return interpretants != rhs.interpretants; + } + + [[nodiscard]] std::optional GetInterpreteeOf(const std::string& aName) const { + for (const auto& [key, value] : interpretants) { + if (value == aName) { + return key; + } + } + return std::nullopt; + } + + int32_t PushBack(const std::string& val) { + // Note: using numeric properties of interpretee + auto newIndex = static_cast(std::ssize(*this) + 1); + while (HasInterpretantFor(newIndex)) { + ++newIndex; + } + interpretants.emplace(newIndex, val); + return newIndex; + } +}; + +} // namespace ccl::semantic \ No newline at end of file diff --git a/ccl/core/include/ccl/semantic/Thesaurus.h b/ccl/core/include/ccl/semantic/Thesaurus.h new file mode 100644 index 0000000..eacc8b8 --- /dev/null +++ b/ccl/core/include/ccl/semantic/Thesaurus.h @@ -0,0 +1,121 @@ +#pragma once + +#include "ccl/semantic/TextConcept.h" +#include "ccl/lang/EntityTermContext.hpp" +#include "ccl/lang/RefsManager.h" +#include "ccl/graph/CGraph.h" + +#include + +namespace ccl::semantic { + +class Thesaurus; + +//! RSCore term context +class TextContext : public lang::EntityTermContext { +public: + explicit TextContext(const Thesaurus& thesaurus) noexcept + : thesaurus{ thesaurus } {} + +private: + const Thesaurus& thesaurus; + +public: + [[nodiscard]] bool Contains(const std::string& entity) const override; + [[nodiscard]] const lang::LexicalTerm* At(const std::string& entity) const override; + [[nodiscard]] std::unordered_map + MatchingTerms(const std::string& input) const override; +}; + +class TextIterator; + +//! System of text definition for concepts +class Thesaurus { + friend class TextIterator; + + // Note: using map for consistent iteration order + using Storage = std::map; + Storage storage{}; + + TextContext context; + mutable graph::UpdatableGraph termGraph; + mutable graph::UpdatableGraph defGraph; + +public: + ~Thesaurus() noexcept = default; + explicit Thesaurus(); + + Thesaurus(const Thesaurus& rhs); + Thesaurus& operator=(const Thesaurus& rhs); + Thesaurus(Thesaurus&& rhs) noexcept; + Thesaurus& operator=(Thesaurus&& rhs) noexcept; + +public: + [[nodiscard]] TextIterator begin() const noexcept; + [[nodiscard]] TextIterator end() const noexcept; + [[nodiscard]] size_t size() const noexcept; + [[nodiscard]] bool empty() const noexcept { return size() == 0; } + + [[nodiscard]] bool Contains(EntityUID entity) const; + [[nodiscard]] std::optional FindAlias(const std::string& alias) const; + + //! requires Contains(entity) == true + [[nodiscard]] const TextConcept& At(EntityUID entity) const; + + [[nodiscard]] const lang::EntityTermContext& Context() const noexcept; + [[nodiscard]] const graph::CGraph& TermGraph() const; + [[nodiscard]] const graph::CGraph& DefGraph() const; + + bool Emplace(EntityUID newID, std::string name, + lang::LexicalTerm term = {}, lang::ManagedText definition = {}); + bool Insert(TextConcept&& cst); + bool InsertCopy(const TextConcept& cst); + void Load(TextConcept&& cst); + void Erase(EntityUID target); + + bool SetAliasFor(EntityUID target, const std::string& newValue, bool substitueMentions = true); + bool SetTermFor(EntityUID target, const std::string& termRef); + bool SetTermFormFor(EntityUID target, const std::string& termRef, const lang::Morphology& form); + bool SetDefinitionFor(EntityUID target, const std::string& textDef); + + void SubstitueAliases(const StrTranslator& old2New); + void Translate(EntityUID target, const StrTranslator& old2New); + void TranslateTerm(EntityUID target, const StrTranslator& old2New); + void TranslateDef(EntityUID target, const StrTranslator& old2New); + void TranslateAll(const StrTranslator& old2New); + + [[nodiscard]] bool HasHomonyms() const; + [[nodiscard]] StrSubstitutes GetHomonyms() const; + + void UpdateState(); + +private: + void OnTermChange(EntityUID target); +}; + +//! Text concept iterator +class TextIterator { + friend class Thesaurus; + using Container = Thesaurus::Storage; + Container::const_iterator iterator; + +private: + explicit TextIterator(Container::const_iterator iter) noexcept; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = TextConcept; + using difference_type = std::ptrdiff_t; + using pointer = const TextConcept*; + using reference = const TextConcept&; + + [[nodiscard]] bool operator==(const TextIterator& iter2) const noexcept; + [[nodiscard]] bool operator!=(const TextIterator& iter2) const noexcept { return !(*this == iter2); } + + TextIterator& operator++() noexcept; + + [[nodiscard]] pointer operator->() const noexcept; + [[nodiscard]] reference operator*() const noexcept; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/rsCalculationFacet.h b/ccl/core/include/ccl/semantic/rsCalculationFacet.h new file mode 100644 index 0000000..e0d930a --- /dev/null +++ b/ccl/core/include/ccl/semantic/rsCalculationFacet.h @@ -0,0 +1,53 @@ +#pragma once + +#include "ccl/Entity.hpp" +#include "ccl/rslang/Interpreter.h" + +namespace ccl::semantic { + +class RSModel; + +//! Evaluation status enumeration +enum class EvalStatus : uint8_t { + UNKNOWN = 0, // + NEVER_CALCULATED = 1, // Интерпретация не вычислялась + INCALCULABLE = 2, // Невозможно вычислить + AXIOM_FAIL = 3, // Значение аксиомы = FALSE (только для аксиом) + EMPTY = 4, // Значение пусто (только для множеств) + HAS_DATA = 5, // Интерпретация вычислена и непуста +}; + +//! Evaluation facet for RSModel +class rsCalculationFacet final : public meta::MutatorFacet { + friend class RSModel; + + SetOfEntities calculatedEntities{}; + std::unique_ptr calculator{ nullptr }; + +public: + explicit rsCalculationFacet(RSModel& core); + +public: + [[nodiscard]] EvalStatus operator()(EntityUID entity) const; + [[nodiscard]] bool WasCalculated(EntityUID entity) const; + + [[nodiscard]] rslang::DataContext Context() const; + void RecalculateAll(); + bool Calculate(EntityUID target); + + [[nodiscard]] size_t Count(EvalStatus status) const; + + // Note: Use ONLY in serialization + void LoadCalulated(const SetOfEntities& calculated) { + calculatedEntities = calculated; + } + +private: + void Erase(EntityUID target) noexcept; + void ResetFor(EntityUID target) noexcept; + +private: + bool CalculateCstInternal(EntityUID target); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/rsModificationFacet.h b/ccl/core/include/ccl/semantic/rsModificationFacet.h new file mode 100644 index 0000000..55f41ab --- /dev/null +++ b/ccl/core/include/ccl/semantic/rsModificationFacet.h @@ -0,0 +1,61 @@ +#pragma once + +#include "ccl/cclMeta.hpp" +#include "ccl/Entity.hpp" + +namespace ccl::semantic { + +class RSForm; +class Thesaurus; + +//! Constituent modification options +struct TrackingFlags { + bool allowEdit{ false }; + + bool term{ false }; + bool definition{ false }; + bool convention{ false }; + + [[nodiscard]] bool operator==(const TrackingFlags& rhs) const noexcept { + return allowEdit == rhs.allowEdit && + term == rhs.term && + definition == rhs.definition && + convention == rhs.convention; + } + [[nodiscard]] bool operator!=(const TrackingFlags& rhs) const noexcept { + return !(*this == rhs); + } +}; + +//! Modifications tracking facet of RSForm +class rsModificationFacet final : public meta::MutatorFacet { + friend class RSForm; + friend class Thesaurus; + + using Container = std::unordered_map; + Container cvs{}; + +public: + explicit rsModificationFacet(RSForm& core) + : MutatorFacet(core) {} + +public: + [[nodiscard]] bool IsTracking(EntityUID entity) const; + [[nodiscard]] const TrackingFlags* operator()(EntityUID entity) const; + [[nodiscard]] TrackingFlags* operator()(EntityUID entity); + + void Track(EntityUID entity, const TrackingFlags& modOpts = {}); + void StopTracking(EntityUID entity) noexcept; + void ResetAll(); + +private: + void LoadFrom(const rsModificationFacet& f2); + void Clear() noexcept; + void Erase(EntityUID target) noexcept; + + void OnTermChange(EntityUID entity); + void OnDefenitionChange(EntityUID entity); + void OnConventionChange(EntityUID entity); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/rsOperationFacet.h b/ccl/core/include/ccl/semantic/rsOperationFacet.h new file mode 100644 index 0000000..099936e --- /dev/null +++ b/ccl/core/include/ccl/semantic/rsOperationFacet.h @@ -0,0 +1,35 @@ +#pragma once + +#include "ccl/ops/EquationOptions.h" +#include "ccl/ops/RSEquationProcessor.h" + +namespace ccl::semantic { + +class RSForm; + +//! Operations facet of RSForm +class rsOperationFacet final : public meta::MutatorFacet { + friend class RSForm; + + std::unique_ptr equationProcessor; + +public: + ~rsOperationFacet() noexcept = default; + rsOperationFacet(const rsOperationFacet&) = delete; + rsOperationFacet& operator=(const rsOperationFacet&) = delete; + + explicit rsOperationFacet(RSForm& core); + +public: + [[nodiscard]] EntityTranslation Identity() const; + + std::optional ExtrapolateFromPrevious(const RSForm& oldShema, + const EntityTranslation& oldToNew); + EntityTranslation MergeWith(const RSForm& schema2); + EntityTranslation DeleteDuplicates(); + + [[nodiscard]] bool IsEquatable(const ops::EquationOptions& equations) const; + std::optional Equate(const ops::EquationOptions& equations); +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/semantic/rsValuesFacet.h b/ccl/core/include/ccl/semantic/rsValuesFacet.h new file mode 100644 index 0000000..92be721 --- /dev/null +++ b/ccl/core/include/ccl/semantic/rsValuesFacet.h @@ -0,0 +1,54 @@ +#pragma once + +#include "ccl/semantic/InterpretationStorage.h" + +namespace ccl::semantic { + +class RSModel; +class rsCalculationFacet; + +//! Constituent values manager facet of RSModel +class rsValuesFacet final : public meta::MutatorFacet { + friend class RSModel; + friend class rsCalculationFacet; + + std::unique_ptr storage{ nullptr }; + std::unordered_map statements{}; + +public: + explicit rsValuesFacet(RSModel& core); + +public: + [[nodiscard]] std::optional SDataFor(EntityUID entity) const; + [[nodiscard]] std::optional StatementFor(EntityUID entity) const; + [[nodiscard]] const TextInterpretation* TextFor(EntityUID entity) const; + + void ResetDataFor(EntityUID target); + + std::optional AddBasicElement(EntityUID target, const std::string& name); + bool SetBasicText(EntityUID target, const TextInterpretation& newInterp); + + // Note: runtime requires CstType == STRUCTURE + bool SetStructureData(EntityUID target, object::StructuredData input); + + // Note: Serialization only!! + void LoadData(EntityUID target, object::StructuredData input); + void LoadData(EntityUID target, bool logicVal); + void LoadData(EntityUID target, const TextInterpretation& newInterp); + +private: + bool SetRSInternal(EntityUID target, const object::StructuredData& input); + bool SetTextInternal(EntityUID target, const TextInterpretation& newInterp); + bool SetStatementInternal(EntityUID target, bool logicVal); + + void Erase(EntityUID target) noexcept; + void ResetFor(EntityUID target); + void PruneStructure(EntityUID target); + void ResetAll(); + void ResetAllExceptCore(); + +private: + [[nodiscard]] bool CheckBasicElements(const object::StructuredData& data, const rslang::Typification& type) const; +}; + +} // namespace ccl::semantic diff --git a/ccl/core/include/ccl/tools/CstNameGenerator.h b/ccl/core/include/ccl/tools/CstNameGenerator.h new file mode 100644 index 0000000..b7e4551 --- /dev/null +++ b/ccl/core/include/ccl/tools/CstNameGenerator.h @@ -0,0 +1,35 @@ +#pragma once + +#include "ccl/semantic/CstType.hpp" + +#include +#include +#include + +namespace ccl::tools { + +//! Constituent name generator +class CstNameGenerator { + std::unordered_set names{}; + +public: + struct NameElements { + const semantic::CstType type{ semantic::CstType::base }; + uint32_t index{0}; + }; + +public: + void Clear() noexcept; + + [[nodiscard]] std::string NewUID(); + void AddUID(const std::string& newUID); + void FreeUID(const std::string& returnUID) noexcept; + [[nodiscard]] bool IsTaken(const std::string& name) const; + + [[nodiscard]] std::string NewNameFor(semantic::CstType type); + + [[nodiscard]] static bool IsNameCorrect(const std::string& name) noexcept; + [[nodiscard]] static std::optional GetTypeForName(const std::string& name); +}; + +} // namespace ccl::tools \ No newline at end of file diff --git a/ccl/core/include/ccl/tools/EntityGenerator.h b/ccl/core/include/ccl/tools/EntityGenerator.h new file mode 100644 index 0000000..71dcecb --- /dev/null +++ b/ccl/core/include/ccl/tools/EntityGenerator.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ccl/Entity.hpp" + +#include + +namespace ccl::tools { + +//! Entity ID generator +class EntityGenerator { + std::uniform_int_distribution<> distribution{ 0, std::numeric_limits::max() }; + SetOfEntities entities{}; + +public: + void Clear() noexcept; + + [[nodiscard]] EntityUID NewUID(); + void AddUID(const EntityUID& newUID); + void FreeUID(const EntityUID& returnUID) noexcept; + [[nodiscard]] bool IsTaken(const EntityUID& uid) const; +}; + +} // namespace ccl::tools \ No newline at end of file diff --git a/ccl/core/include/ccl/tools/EnumJSON.hpp b/ccl/core/include/ccl/tools/EnumJSON.hpp new file mode 100644 index 0000000..e006aed --- /dev/null +++ b/ccl/core/include/ccl/tools/EnumJSON.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include "ccl/Source.hpp" +#include "ccl/semantic/Schema.h" +#include "ccl/semantic/CstType.hpp" +#include "ccl/ops/EquationOptions.h" +#include "ccl/lang/Morphology.h" +#include "ccl/rslang/ValueClass.hpp" + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 4051 4060 ) + #pragma warning( disable : 26416 26433 26434 26438 26440 26443 26444 26446 26447 ) + #pragma warning( disable : 26454 26456 26462 26473 26475 26476 ) + #pragma warning( disable : 26481 26482 26493 26494 26495 26496 26800 26819 28020 ) +#endif + +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-conversion" +#endif + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push +#endif + +#include "nlohmann/json.hpp" + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 26440 26495 ) // Note: Disable warnings because of lambdas in macros +#endif + +namespace ccl::rslang { + +NLOHMANN_JSON_SERIALIZE_ENUM( + ValueClass, + { + { ValueClass::invalid, "invalid" }, + { ValueClass::value, "value" }, + { ValueClass::props, "property" }, + } +) + +NLOHMANN_JSON_SERIALIZE_ENUM( + Syntax, + { + { Syntax::UNDEF, "undefined" }, + { Syntax::ASCII, "ascii" }, + { Syntax::MATH, "math" }, + } +) + +} // namespace ccl::rslang + +namespace ccl::semantic { + +NLOHMANN_JSON_SERIALIZE_ENUM( + ParsingStatus, + { + { ParsingStatus::UNKNOWN, "undefined" }, + { ParsingStatus::VERIFIED, "verified" }, + { ParsingStatus::INCORRECT, "incorrect" }, + } +) + +NLOHMANN_JSON_SERIALIZE_ENUM( + CstType, + { + { CstType::base, "basic" }, + { CstType::constant, "constant" }, + { CstType::structured, "structure" }, + { CstType::axiom, "axiom" }, + { CstType::term, "term" }, + { CstType::function, "function" }, + { CstType::theorem, "theorem" }, + { CstType::predicate, "predicate" }, + } +) + +} // namespace ccl::semantic + +namespace ccl::src { + +NLOHMANN_JSON_SERIALIZE_ENUM( + DataType, + { + { DataType::tba, "tba" }, + { DataType::rsSchema, "schema" }, + } +) + +NLOHMANN_JSON_SERIALIZE_ENUM( + SrcType, + { + { SrcType::tba, "tba" }, + { SrcType::rsDoc, "rsDocument" }, + } +) + +} // namespace ccl::src + +namespace ccl::ops { + +NLOHMANN_JSON_SERIALIZE_ENUM( + Equation::Mode, + { + { Equation::Mode::keepHier, "keepSecond" }, + { Equation::Mode::keepDel, "keepFirst" }, + { Equation::Mode::createNew, "createNew" }, + } +) + +NLOHMANN_JSON_SERIALIZE_ENUM( + Type, + { + { Type::tba, "tba" }, + { Type::rsMerge, "rsMerge"}, + { Type::rsSynt, "rsSynt" }, + } +) + +} // namespace ccl::ops + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif \ No newline at end of file diff --git a/ccl/core/include/ccl/tools/JSON.h b/ccl/core/include/ccl/tools/JSON.h new file mode 100644 index 0000000..7f22081 --- /dev/null +++ b/ccl/core/include/ccl/tools/JSON.h @@ -0,0 +1,102 @@ +#pragma once + +#include "ccl/tools/EnumJSON.hpp" + +#include "ccl/semantic/RSModel.h" +#include "ccl/semantic/RSForm.h" +#include "ccl/oss/OSSchema.h" +#include "ccl/ops/RSOperations.h" +#include "ccl/rslang/SDataCompact.h" + +namespace ccl { + +namespace semantic { + +void to_json(nlohmann::ordered_json& object, const RSModel& model); +void from_json(const nlohmann::ordered_json& object, RSModel& model); + +void to_json(nlohmann::ordered_json& object, const RSForm& schema); +void from_json(const nlohmann::ordered_json& object, RSForm& schema); + +void to_json(nlohmann::ordered_json& object, const RSCore& core); +void from_json(const nlohmann::ordered_json& object, RSCore& core); + +void to_json(nlohmann::ordered_json& object, const TextInterpretation& text); +void from_json(const nlohmann::ordered_json& object, TextInterpretation& text); + +void to_json(nlohmann::ordered_json& object, const ConceptRecord& record); +void from_json(const nlohmann::ordered_json& object, ConceptRecord& record); + +void to_json(nlohmann::ordered_json& object, const TrackingFlags& mods); +void from_json(const nlohmann::ordered_json& object, TrackingFlags& mods); + +} // namespace ccl::semantic + +namespace rslang { + +void to_json(nlohmann::ordered_json& object, const ExpressionType& type); +void to_json(nlohmann::ordered_json& object, const Typification& typif); +void to_json(nlohmann::ordered_json& object, const FunctionArguments& args); +void to_json(nlohmann::ordered_json& object, const TokenData& data); +void to_json(nlohmann::ordered_json& object, const SyntaxTree& ast); +void to_json(nlohmann::ordered_json& object, const Error& error); + +} // namespace ccl::rslang + +namespace lang { + +void to_json(nlohmann::ordered_json& object, const LexicalTerm& term); +void from_json(const nlohmann::ordered_json& object, LexicalTerm& term); + +void to_json(nlohmann::ordered_json& object, const ManagedText& text); +void from_json(const nlohmann::ordered_json& object, ManagedText& text); + +} // namespace ccl::lang + +namespace src { + +void to_json(nlohmann::ordered_json& object, const Handle& srcHandle); +void from_json(const nlohmann::ordered_json& object, Handle& srcHandle); + +} // namespace ccl::src + +namespace oss { + +void to_json(nlohmann::ordered_json& object, const OSSchema& oss); +void from_json(const nlohmann::ordered_json& object, OSSchema& oss); + +void to_json(nlohmann::ordered_json& object, const Pict& pict); +void from_json(const nlohmann::ordered_json& object, Pict& pict); + +void to_json(nlohmann::ordered_json& object, const MediaLink& link); +void from_json(const nlohmann::ordered_json& object, MediaLink& link); + +void to_json(nlohmann::ordered_json& object, const OperationHandle& operation); +void from_json(const nlohmann::ordered_json& object, OperationHandle& operation); + +void to_json(nlohmann::ordered_json& object, const Grid& grid); +void from_json(const nlohmann::ordered_json& object, Grid& grid); + +void to_json(nlohmann::ordered_json& object, const GridPosition& position); +void from_json(const nlohmann::ordered_json& object, GridPosition& position); + +} // namespace ccl::oss + +namespace ops { + +void to_json(nlohmann::ordered_json& object, const TranslationData& translations); +void from_json(const nlohmann::ordered_json& object, TranslationData& translations); + +void to_json(nlohmann::ordered_json& object, const EquationOptions& equations); +void from_json(const nlohmann::ordered_json& object, EquationOptions& equations); + +void to_json(nlohmann::ordered_json& object, const Equation& equation); +void from_json(const nlohmann::ordered_json& object, Equation& equation); + + +} // namespace ccl::ops + +void to_json(nlohmann::ordered_json& object, const EntityTranslation& translation); +void from_json(const nlohmann::ordered_json& object, EntityTranslation& translation); + +} // namespace ccl \ No newline at end of file diff --git a/ccl/core/include/nlohmann/json.hpp b/ccl/core/include/nlohmann/json.hpp new file mode 100644 index 0000000..93a3d67 --- /dev/null +++ b/ccl/core/include/nlohmann/json.hpp @@ -0,0 +1,24766 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.2.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple +#include // char_traits + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector, // cppcheck-suppress syntaxError + class CustomBaseClass = void> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template