mirror of
https://github.com/IRBorisov/ConceptCore.git
synced 2025-06-25 16:50:36 +03:00
Initial commit
This commit is contained in:
parent
ac0e5cfd2b
commit
9c09995d17
39
.clang-tidy
Normal file
39
.clang-tidy
Normal file
|
@ -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"
|
29
.dockerignore
Normal file
29
.dockerignore
Normal file
|
@ -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
|
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
|
@ -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
|
17
.vscode/settings.json
vendored
Normal file
17
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"DCMAKE",
|
||||
"debool",
|
||||
"Decartian",
|
||||
"defexpr",
|
||||
"gtest",
|
||||
"MSVC",
|
||||
"nlohmann",
|
||||
"noteq",
|
||||
"notsubset",
|
||||
"pybind",
|
||||
"pyconcept",
|
||||
"rslang",
|
||||
"symmdiff"
|
||||
]
|
||||
}
|
152
CCL-Full.sln
Normal file
152
CCL-Full.sln
Normal file
|
@ -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
|
103
Dockerfile
Normal file
103
Dockerfile
Normal file
|
@ -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"]
|
2
LICENSE
2
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
|
||||
|
|
39
README.md
Normal file
39
README.md
Normal file
|
@ -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
|
88
ccl/CMakeLists.txt
Normal file
88
ccl/CMakeLists.txt
Normal file
|
@ -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}/$<CONFIG>/${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()
|
26
ccl/cclCommons/CMakeLists.txt
Normal file
26
ccl/cclCommons/CMakeLists.txt
Normal file
|
@ -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()
|
9
ccl/cclCommons/conanfile.txt
Normal file
9
ccl/cclCommons/conanfile.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
[requires]
|
||||
gtest/1.14.0
|
||||
|
||||
[generators]
|
||||
CMakeDeps
|
||||
CMakeToolchain
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
337
ccl/cclCommons/include/ccl/Strings.hpp
Normal file
337
ccl/cclCommons/include/ccl/Strings.hpp
Normal file
|
@ -0,0 +1,337 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
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<const char*>(input) };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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<std::string>(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<std::string_view> SplitBySymbol(std::string_view text, char delim = ',') {
|
||||
std::vector<std::string_view> 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<int32_t>(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<StrRange> 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<StrRange>& 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<size_t>(UTF8CharSize(static_cast<unsigned char>(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
|
32
ccl/cclCommons/include/ccl/Substitutes.hpp
Normal file
32
ccl/cclCommons/include/ccl/Substitutes.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace ccl {
|
||||
|
||||
using StrSubstitutes = std::unordered_map<std::string, std::string>;
|
||||
using StrTranslator = std::function<std::optional<std::string>(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
|
52
ccl/cclCommons/include/ccl/cclChange.hpp
Normal file
52
ccl/cclCommons/include/ccl/cclChange.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/cclTypes.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
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<uint32_t>(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
|
371
ccl/cclCommons/include/ccl/cclMeta.hpp
Normal file
371
ccl/cclCommons/include/ccl/cclMeta.hpp
Normal file
|
@ -0,0 +1,371 @@
|
|||
#pragma once
|
||||
// Metaprogramming tools
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ccl::meta {
|
||||
|
||||
//! Basic identity class for template overloading/specializations
|
||||
template<typename T>
|
||||
struct Identity { using type = T; };
|
||||
|
||||
//! Naive propagate_const implementation aimed at unique_ptr
|
||||
template<typename T>
|
||||
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<typename Up,
|
||||
typename std::enable_if_t<std::is_constructible_v<T, Up&&>>>
|
||||
PropagateConst(Up&& up) // NOLINT(google-explicit-constructor, hicpp-explicit-conversions, bugprone-forwarding-reference-overload)
|
||||
: pointer{ std::forward<Up>(up) } {}
|
||||
|
||||
template<typename Up,
|
||||
typename std::enable_if_t<std::is_constructible_v<T, Up&&>>>
|
||||
PropagateConst(PropagateConst<Up>&& up) // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
: pointer{ std::move(up.pointer) } {}
|
||||
|
||||
template<typename Up,
|
||||
typename std::enable_if_t<std::is_constructible_v<T, Up&&>>>
|
||||
constexpr PropagateConst& operator=(Up&& up) {
|
||||
pointer = std::forward<Up>(up);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Up,
|
||||
typename std::enable_if_t<std::is_constructible_v<T, Up&&>>>
|
||||
constexpr PropagateConst& operator=(PropagateConst<Up>&& up) {
|
||||
pointer = std::move(up.pointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
using ElementType = std::remove_reference_t<decltype(*std::declval<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<T>& 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<typename T>
|
||||
using UniqueCPPtr = PropagateConst<std::unique_ptr<T>>;
|
||||
|
||||
//! Grouping multiple overloaded lambas
|
||||
/*
|
||||
see https://www.youtube.com/watch?v=XjOVebhUOY around 20:30
|
||||
*/
|
||||
template <typename ...Ops>
|
||||
struct Overloads : Ops... {
|
||||
using Ops::operator()...;
|
||||
};
|
||||
template <typename ...Ops>
|
||||
Overloads(Ops...)->Overloads<Ops...>;
|
||||
|
||||
//! Apply function object to tuples created from elements container
|
||||
template <typename Container,
|
||||
typename Function,
|
||||
typename Value = typename Container::value_type>
|
||||
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 <typename Base, template<typename> class crtpType>
|
||||
struct crtp {
|
||||
[[nodiscard]] Base& BaseT() noexcept { return static_cast<Base&>(*this); }
|
||||
[[nodiscard]] const Base& BaseT() const noexcept { return static_cast<Base const&>(*this); }
|
||||
};
|
||||
|
||||
//! Abstract strong type
|
||||
/*
|
||||
see https://github.com/joboccara/NamedType
|
||||
*/
|
||||
template <typename T>
|
||||
struct Incrementable : crtp<T, Incrementable> {
|
||||
T& operator+=(const T& other) { this->BaseT().get() += other.get(); return this->BaseT(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PreIncrementable : crtp<T, PreIncrementable> {
|
||||
T& operator++() { ++this->BaseT().get(); return this->BaseT(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Addable : crtp<T, Addable> {
|
||||
T operator+(const T& other) const { return T(this->BaseT().get() + other.get()); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Subtractable : crtp<T, Subtractable> {
|
||||
T operator-(const T& other) const { return T(this->BaseT().get() - other.get()); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Multiplicable : crtp<T, Multiplicable> {
|
||||
T operator*(const T& other) const { return T(this->BaseT().get() * other.get()); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Comparable : crtp<T, Comparable> {
|
||||
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 <typename T>
|
||||
struct Orderable : crtp<T, Orderable> {
|
||||
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 <typename T, T... args>
|
||||
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<size_t>(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<typename Core>
|
||||
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<typename Core>
|
||||
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<typename Value>
|
||||
class PolyFCIterator {
|
||||
struct ImplConcept;
|
||||
template<typename Iter> struct ImplModel;
|
||||
|
||||
std::unique_ptr<ImplConcept> impl{ nullptr };
|
||||
|
||||
public:
|
||||
~PolyFCIterator() noexcept = default;
|
||||
PolyFCIterator(const PolyFCIterator<Value>& rhs)
|
||||
: impl{ rhs.impl->Clone() } {}
|
||||
PolyFCIterator& operator=(const PolyFCIterator<Value>& rhs) {
|
||||
if (this == &rhs) {
|
||||
return *this;
|
||||
}
|
||||
impl = rhs.impl->Clone();
|
||||
return *this;
|
||||
}
|
||||
PolyFCIterator(PolyFCIterator<Value>&&) noexcept = default;
|
||||
PolyFCIterator& operator=(PolyFCIterator<Value>&&) noexcept = default;
|
||||
|
||||
template<typename Iter>
|
||||
explicit PolyFCIterator(const Iter& iter)
|
||||
: impl{ std::make_unique<ImplModel<Iter>>(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<ImplConcept> Clone() const = 0;
|
||||
[[nodiscard]] virtual const std::type_info& Type() const noexcept = 0;
|
||||
[[nodiscard]] virtual const void* Address() const noexcept = 0;
|
||||
};
|
||||
|
||||
template<typename Iter>
|
||||
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<const ImplModel*>(rp)->iter;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ImplConcept> Clone() const override {
|
||||
return std::make_unique<ImplModel>(*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<Value>& operator++() {
|
||||
impl->Next();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const PolyFCIterator<Value>& rhs) const {
|
||||
return impl->Type() == rhs.impl->Type() && impl->Equal(rhs.impl->Address());
|
||||
}
|
||||
bool operator!=(const PolyFCIterator<Value>& r) const {
|
||||
return !(*this == r);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ccl::meta
|
239
ccl/cclCommons/include/ccl/cclTypes.hpp
Normal file
239
ccl/cclCommons/include/ccl/cclTypes.hpp
Normal file
|
@ -0,0 +1,239 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
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 <typename Key, typename Value, std::size_t Size>
|
||||
struct StaticMap {
|
||||
using DataType = std::array<std::pair<Key, Value>, 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<typename T>
|
||||
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<uint16_t>;
|
||||
|
||||
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<Observer*> 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
|
24
ccl/cclCommons/test/CMakeLists.txt
Normal file
24
ccl/cclCommons/test/CMakeLists.txt
Normal file
|
@ -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)
|
211
ccl/cclCommons/test/cclCommonsTest.vcxproj
Normal file
211
ccl/cclCommons/test/cclCommonsTest.vcxproj
Normal file
|
@ -0,0 +1,211 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{53A380CF-B599-4170-89B1-642F1C3772E1}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<ProjectName>cclCommonsTest</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<VCToolsVersion />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<VCToolsVersion />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets" Condition="Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testGuard.cpp" />
|
||||
<ClCompile Include="src\testObserver.cpp" />
|
||||
<ClCompile Include="src\testPropagateConst.cpp" />
|
||||
<ClCompile Include="src\testStaticMap.cpp" />
|
||||
<ClCompile Include="src\testStrings.cpp" />
|
||||
<ClCompile Include="src\testSubstitutes.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\ccl\cclChange.hpp" />
|
||||
<ClInclude Include="..\include\ccl\cclMeta.hpp" />
|
||||
<ClInclude Include="..\include\ccl\cclTypes.hpp" />
|
||||
<ClInclude Include="..\include\ccl\Strings.hpp" />
|
||||
<ClInclude Include="..\include\ccl\Substitutes.hpp" />
|
||||
<ClInclude Include="utils\FakeObserver.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>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}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
54
ccl/cclCommons/test/cclCommonsTest.vcxproj.filters
Normal file
54
ccl/cclCommons/test/cclCommonsTest.vcxproj.filters
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{ed04b33d-515f-46b0-aad1-54dcbc55a5fd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="utils">
|
||||
<UniqueIdentifier>{4c4173ff-1f15-4919-90b9-3d43cc164f84}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{be31e9f2-602c-4c10-b9ed-7407342449f4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testGuard.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testObserver.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testPropagateConst.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testSubstitutes.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testStrings.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testStaticMap.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utils\FakeObserver.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\ccl\cclMeta.hpp">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\ccl\cclTypes.hpp">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\ccl\cclChange.hpp">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\ccl\Substitutes.hpp">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\ccl\Strings.hpp">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
4
ccl/cclCommons/test/packages.config
Normal file
4
ccl/cclCommons/test/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.7" targetFramework="native" />
|
||||
</packages>
|
69
ccl/cclCommons/test/src/testGuard.cpp
Normal file
69
ccl/cclCommons/test/src/testGuard.cpp
Normal file
|
@ -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());
|
||||
}
|
83
ccl/cclCommons/test/src/testObserver.cpp
Normal file
83
ccl/cclCommons/test/src/testObserver.cpp
Normal file
|
@ -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);
|
||||
}
|
126
ccl/cclCommons/test/src/testPropagateConst.cpp
Normal file
126
ccl/cclCommons/test/src/testPropagateConst.cpp
Normal file
|
@ -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<int32_t> intCP{ std::make_unique<int32_t>(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<int32_t*>(intCP), constRef.get());
|
||||
EXPECT_EQ(static_cast<const int32_t*>(constRef), constRef.get());
|
||||
}
|
||||
|
||||
TEST(UTPropagateConst, Nullptr) {
|
||||
using ccl::meta::UniqueCPPtr;
|
||||
const UniqueCPPtr<int32_t> intPtr{};
|
||||
EXPECT_TRUE(intPtr == nullptr);
|
||||
EXPECT_FALSE(intPtr != nullptr);
|
||||
EXPECT_EQ(intPtr, UniqueCPPtr<int32_t>(nullptr));
|
||||
|
||||
UniqueCPPtr<int32_t> notNull{ std::make_unique<int32_t>(42) };
|
||||
EXPECT_FALSE(notNull == nullptr);
|
||||
EXPECT_TRUE(notNull != nullptr);
|
||||
|
||||
notNull = nullptr;
|
||||
EXPECT_TRUE(notNull == nullptr);
|
||||
|
||||
notNull = std::make_unique<int32_t>(0);
|
||||
EXPECT_FALSE(notNull == nullptr);
|
||||
}
|
||||
|
||||
TEST(UTPropagateConst, PointerEquality) {
|
||||
using ccl::meta::UniqueCPPtr;
|
||||
UniqueCPPtr<int32_t> int1{ std::make_unique<int32_t>(42) };
|
||||
UniqueCPPtr<int32_t> int2{ std::make_unique<int32_t>(42) };
|
||||
UniqueCPPtr<int32_t> int3{ std::make_unique<int32_t>(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<int32_t> int1{ std::make_unique<int32_t>(42) };
|
||||
std::swap(int1, int1);
|
||||
EXPECT_EQ(*int1, 42);
|
||||
|
||||
UniqueCPPtr<int32_t> int2{ std::make_unique<int32_t>(1337) };
|
||||
std::swap(int1, int2);
|
||||
EXPECT_EQ(*int2, 42);
|
||||
EXPECT_EQ(*int1, 1337);
|
||||
}
|
||||
|
||||
TEST(UTPropagateConst, Propagation) {
|
||||
using ccl::meta::UniqueCPPtr;
|
||||
UniqueCPPtr<Base> nonConstPtr{ std::make_unique<Base>() };
|
||||
const auto& constRef = nonConstPtr;
|
||||
EXPECT_EQ(nonConstPtr->overloadedFunc(), 43);
|
||||
EXPECT_EQ(constRef->overloadedFunc(), 42);
|
||||
}
|
||||
|
||||
TEST(UTPropagateConst, Polymorphism) {
|
||||
using ccl::meta::UniqueCPPtr;
|
||||
UniqueCPPtr<Base> basePtrToDerived1{}, basePtrToDerived2{};
|
||||
basePtrToDerived1 = UniqueCPPtr<Base>{ std::make_unique<Derived1>() };
|
||||
basePtrToDerived2 = UniqueCPPtr<Base>{ std::make_unique<Derived2>() };
|
||||
|
||||
ASSERT_FALSE(dynamic_cast<Derived1*>(basePtrToDerived1.get()) == nullptr);
|
||||
EXPECT_TRUE(dynamic_cast<Derived2*>(basePtrToDerived1.get()) == nullptr);
|
||||
EXPECT_EQ(dynamic_cast<Derived1*>(basePtrToDerived1.get())->additionalState, 42);
|
||||
EXPECT_EQ(dynamic_cast<Derived2*>(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);
|
||||
}
|
49
ccl/cclCommons/test/src/testStaticMap.cpp
Normal file
49
ccl/cclCommons/test/src/testStaticMap.cpp
Normal file
|
@ -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<std::string_view, int32_t, 4>;
|
||||
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
|
384
ccl/cclCommons/test/src/testStrings.cpp
Normal file
384
ccl/cclCommons/test/src/testStrings.cpp
Normal file
|
@ -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<unsigned char>(std::string("a").at(0U))), 1);
|
||||
EXPECT_EQ(ccl::UTF8CharSize(static_cast<unsigned char>(std::string("1").at(0U))), 1);
|
||||
EXPECT_EQ(ccl::UTF8CharSize(static_cast<unsigned char>(u8"\u0435"_c17.at(0U))), 2);
|
||||
EXPECT_EQ(ccl::UTF8CharSize(static_cast<unsigned char>(std::string("\xE2\x84\xAC").at(0U))), 3);
|
||||
EXPECT_EQ(ccl::UTF8CharSize(static_cast<unsigned char>(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"));
|
||||
}
|
22
ccl/cclCommons/test/src/testSubstitutes.cpp
Normal file
22
ccl/cclCommons/test/src/testSubstitutes.cpp
Normal file
|
@ -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");
|
||||
}
|
12
ccl/cclCommons/test/unity/cclCommonsTest.cpp
Normal file
12
ccl/cclCommons/test/unity/cclCommonsTest.cpp
Normal file
|
@ -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"
|
23
ccl/cclCommons/test/utils/FakeObserver.hpp
Normal file
23
ccl/cclCommons/test/utils/FakeObserver.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/cclTypes.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
struct FakeObserver : ccl::types::Observer {
|
||||
std::vector<uint32_t> 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); }
|
||||
};
|
75
ccl/cclGraph/CMakeLists.txt
Normal file
75
ccl/cclGraph/CMakeLists.txt
Normal file
|
@ -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}/$<CONFIG>/${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()
|
193
ccl/cclGraph/cclGraph.vcxproj
Normal file
193
ccl/cclGraph/cclGraph.vcxproj
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\Entity.hpp" />
|
||||
<ClInclude Include="include\ccl\graph\CGraph.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CGraph.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{7E1D5338-F819-4C96-B461-9EAAB8D02E1D}</ProjectGuid>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>cclGraph</RootNamespace>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header</AdditionalIncludeDirectories>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include</AdditionalIncludeDirectories>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header</AdditionalIncludeDirectories>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include</AdditionalIncludeDirectories>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
26
ccl/cclGraph/cclGraph.vcxproj.filters
Normal file
26
ccl/cclGraph/cclGraph.vcxproj.filters
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<None Include="VSCustom.ruleset" />
|
||||
<None Include="Jenkinsfile.groovy" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Graph">
|
||||
<UniqueIdentifier>{f0a3dd37-e5ae-4a37-ab65-d574c8dfe252}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\graph\CGraph.h">
|
||||
<Filter>Graph</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\Entity.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CGraph.cpp">
|
||||
<Filter>Graph</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
9
ccl/cclGraph/conanfile.txt
Normal file
9
ccl/cclGraph/conanfile.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
[requires]
|
||||
gtest/1.14.0
|
||||
|
||||
[generators]
|
||||
CMakeDeps
|
||||
CMakeToolchain
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
100
ccl/cclGraph/include/ccl/Entity.hpp
Normal file
100
ccl/cclGraph/include/ccl/Entity.hpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ccl {
|
||||
//! Entity identifier
|
||||
using EntityUID = uint32_t;
|
||||
|
||||
//! Unordered set of entities
|
||||
using SetOfEntities = std::unordered_set<EntityUID>;
|
||||
|
||||
//! Ordered vector of entities
|
||||
using VectorOfEntities = std::vector<EntityUID>;
|
||||
|
||||
class EntityTranslation {
|
||||
using Container = std::unordered_map<EntityUID, EntityUID>;
|
||||
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<std::optional<EntityUID>(const std::string&)>;
|
||||
using Func_UID2Name = std::function<std::optional<std::string>(EntityUID)>;
|
||||
|
||||
} // namespace ccl::tag
|
95
ccl/cclGraph/include/ccl/graph/CGraph.h
Normal file
95
ccl/cclGraph/include/ccl/graph/CGraph.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/Entity.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace ccl::graph {
|
||||
|
||||
using VertexIndex = int32_t;
|
||||
|
||||
//! Entity connections graph
|
||||
class CGraph {
|
||||
struct Vertex {
|
||||
EntityUID uid{};
|
||||
bool isValid{ true };
|
||||
std::vector<VertexIndex> inputs{};
|
||||
std::vector<VertexIndex> outputs{};
|
||||
|
||||
Vertex() = default;
|
||||
explicit constexpr Vertex(const EntityUID uid) : uid{ uid } {}
|
||||
};
|
||||
|
||||
std::vector<Vertex> graph{};
|
||||
std::unordered_map<EntityUID, VertexIndex> verticies{};
|
||||
|
||||
public:
|
||||
using UnorderedItems = SetOfEntities;
|
||||
using OrderedItems = VectorOfEntities;
|
||||
using ItemsGroup = std::vector<UnorderedItems>;
|
||||
|
||||
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<VertexIndex> InternalOrder() const;
|
||||
};
|
||||
|
||||
template<typename InputIt, typename OutputIt>
|
||||
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<UnorderedItems(EntityUID)> updater;
|
||||
bool invalid{ false };
|
||||
|
||||
public:
|
||||
explicit UpdatableGraph(std::function<UnorderedItems(EntityUID)> 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
|
332
ccl/cclGraph/src/CGraph.cpp
Normal file
332
ccl/cclGraph/src/CGraph.cpp
Normal file
|
@ -0,0 +1,332 @@
|
|||
#include "ccl/graph/CGraph.h"
|
||||
|
||||
#include <numeric>
|
||||
#include <iterator>
|
||||
|
||||
// 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<VertexIndex>(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<VertexIndex>(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<VertexIndex>(ssize(item.outputs)); });
|
||||
}
|
||||
|
||||
bool CGraph::HasLoop() const {
|
||||
std::vector<int8_t> status(size(graph), 0);
|
||||
std::vector<VertexIndex> 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<VertexIndex> toVisit{};
|
||||
std::vector<bool> 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<VertexIndex> toVisit{};
|
||||
std::vector<bool> 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<VertexIndex> CGraph::InternalOrder() const {
|
||||
std::vector<VertexIndex> outOrder{};
|
||||
outOrder.reserve(size(verticies));
|
||||
|
||||
std::vector<VertexIndex> toVisit{};
|
||||
std::vector<int8_t> 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<bool> marked(size(graph), false);
|
||||
std::vector<VertexIndex> toVisit{};
|
||||
std::vector<VertexIndex> 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<UnorderedItems(const EntityUID)> 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
|
26
ccl/cclGraph/test/CMakeLists.txt
Normal file
26
ccl/cclGraph/test/CMakeLists.txt
Normal file
|
@ -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)
|
215
ccl/cclGraph/test/cclGraphTest.vcxproj
Normal file
215
ccl/cclGraph/test/cclGraphTest.vcxproj
Normal file
|
@ -0,0 +1,215 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5A2501C1-FEFB-4B14-A94D-E8F19ADEA239}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<ProjectName>cclGraphTest</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets" Condition="Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
<Text Include="ImportGTest.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testConnectionsGraph.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\cclGraph.vcxproj">
|
||||
<Project>{7e1d5338-f819-4c96-b461-9eaab8d02e1d}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\include;..\header;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>cclGraphd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\include;..\header;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>cclGraphd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\include;..\header;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalDependencies>cclGraph.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\include;..\header;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalDependencies>cclGraph.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>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}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
20
ccl/cclGraph/test/cclGraphTest.vcxproj.filters
Normal file
20
ccl/cclGraph/test/cclGraphTest.vcxproj.filters
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Text Include="ImportGTest.txt" />
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{ed04b33d-515f-46b0-aad1-54dcbc55a5fd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testConnectionsGraph.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
4
ccl/cclGraph/test/packages.config
Normal file
4
ccl/cclGraph/test/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.7" targetFramework="native" />
|
||||
</packages>
|
350
ccl/cclGraph/test/src/testConnectionsGraph.cpp
Normal file
350
ccl/cclGraph/test/src/testConnectionsGraph.cpp
Normal file
|
@ -0,0 +1,350 @@
|
|||
#define GTEST_LANG_CXX11 1
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ccl/graph/CGraph.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
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<ccl::SetOfEntities> 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]));
|
||||
}
|
75
ccl/cclLang/CMakeLists.txt
Normal file
75
ccl/cclLang/CMakeLists.txt
Normal file
|
@ -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}/$<CONFIG>/${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()
|
209
ccl/cclLang/cclLang.vcxproj
Normal file
209
ccl/cclLang/cclLang.vcxproj
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\lang\EntityTermContext.hpp" />
|
||||
<ClInclude Include="include\ccl\lang\LexicalTerm.h" />
|
||||
<ClInclude Include="include\ccl\lang\Literals.h" />
|
||||
<ClInclude Include="include\ccl\lang\ManagedText.h" />
|
||||
<ClInclude Include="include\ccl\lang\Morphology.h" />
|
||||
<ClInclude Include="include\ccl\lang\Reference.h" />
|
||||
<ClInclude Include="include\ccl\lang\RefsManager.h" />
|
||||
<ClInclude Include="include\ccl\lang\TextEnvironment.h" />
|
||||
<ClInclude Include="include\ccl\lang\TextProcessor.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\LexicalTerm.cpp" />
|
||||
<ClCompile Include="src\Literals.cpp" />
|
||||
<ClCompile Include="src\ManagedText.cpp" />
|
||||
<ClCompile Include="src\Morphology.cpp" />
|
||||
<ClCompile Include="src\Reference.cpp" />
|
||||
<ClCompile Include="src\RefsManager.cpp" />
|
||||
<ClCompile Include="src\TextEnvironment.cpp" />
|
||||
<ClCompile Include="src\TextProcessor.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<ProjectGuid>{76B03803-56CC-47C2-A8F0-2241FCAF2898}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>cclLang</RootNamespace>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header;..\cclCommons\include</AdditionalIncludeDirectories>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header;..\cclCommons\include</AdditionalIncludeDirectories>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header;..\cclCommons\include</AdditionalIncludeDirectories>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalIncludeDirectories>include;header;..\cclCommons\include</AdditionalIncludeDirectories>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include
|
||||
xcopy /y /s /q /i ..\cclCommons\include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
66
ccl/cclLang/cclLang.vcxproj.filters
Normal file
66
ccl/cclLang/cclLang.vcxproj.filters
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="lang">
|
||||
<UniqueIdentifier>{3c85ab44-bb88-4509-be90-8f248199ac3f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="env">
|
||||
<UniqueIdentifier>{5ea8ccaf-0a49-441e-8a3a-bb300790ffa4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\lang\Reference.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\RefsManager.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\EntityTermContext.hpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\LexicalTerm.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\ManagedText.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\TextProcessor.h">
|
||||
<Filter>env</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\TextEnvironment.h">
|
||||
<Filter>env</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\Morphology.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\lang\Literals.h">
|
||||
<Filter>lang</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Reference.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\RefsManager.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\LexicalTerm.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ManagedText.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\TextProcessor.cpp">
|
||||
<Filter>env</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\TextEnvironment.cpp">
|
||||
<Filter>env</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Morphology.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Literals.cpp">
|
||||
<Filter>lang</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
9
ccl/cclLang/conanfile.txt
Normal file
9
ccl/cclLang/conanfile.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
[requires]
|
||||
gtest/1.14.0
|
||||
|
||||
[generators]
|
||||
CMakeDeps
|
||||
CMakeToolchain
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
48
ccl/cclLang/include/ccl/lang/EntityTermContext.hpp
Normal file
48
ccl/cclLang/include/ccl/lang/EntityTermContext.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/lang/Morphology.h"
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
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<std::string, std::string>
|
||||
MatchingTerms(const std::string& /*input*/) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
} // namespace ccl::lang
|
59
ccl/cclLang/include/ccl/lang/LexicalTerm.h
Normal file
59
ccl/cclLang/include/ccl/lang/LexicalTerm.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/lang/Morphology.h"
|
||||
#include "ccl/lang/ManagedText.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ccl::lang {
|
||||
|
||||
class EntityTermContext;
|
||||
|
||||
//! Complex term with managed text and cached resolution
|
||||
class LexicalTerm {
|
||||
using Forms = std::unordered_map<Morphology, std::string>;
|
||||
|
||||
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<Morphology, std::string>& 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
|
14
ccl/cclLang/include/ccl/lang/Literals.h
Normal file
14
ccl/cclLang/include/ccl/lang/Literals.h
Normal file
|
@ -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
|
41
ccl/cclLang/include/ccl/lang/ManagedText.h
Normal file
41
ccl/cclLang/include/ccl/lang/ManagedText.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/Substitutes.hpp"
|
||||
#include "ccl/lang/Reference.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
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<std::string> Referals() const;
|
||||
};
|
||||
|
||||
} // namespace ccl::lang
|
191
ccl/cclLang/include/ccl/lang/Morphology.h
Normal file
191
ccl/cclLang/include/ccl/lang/Morphology.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#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<std::string_view, 36> 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<std::string_view, Grammem, GRAMMEM_COUNT>;
|
||||
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<size_t>(gram));
|
||||
}
|
||||
|
||||
//! Morphology parameters for a word or collation of words
|
||||
struct Morphology {
|
||||
std::set<Grammem> tags{};
|
||||
|
||||
Morphology() = default;
|
||||
explicit Morphology(std::initializer_list<Grammem> init) noexcept // NOLINT
|
||||
: tags{ init } {}
|
||||
explicit Morphology(std::string_view tagsText);
|
||||
explicit Morphology(const std::vector<std::string_view>& 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<Grammem, 18> 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<Grammem, 6> ALL_CASES = {
|
||||
Grammem::nomn, // именительный | Кто?, Что? | (хомяк) ест
|
||||
Grammem::gent, // родительный | Кого? Чего? | у нас нет (хомяка)
|
||||
Grammem::datv, // дательный | Кому? Чему? | сказать (хомяку) спасибо
|
||||
Grammem::ablt, // винительный | Кого? Что? | тигр ест (хомяка)
|
||||
Grammem::accs, // творительный | Кем? Чем? | зерно съедено (хомяком)
|
||||
Grammem::loct // предложный | О ком? О чём? | хомяка несут в (коробке)
|
||||
};
|
||||
|
||||
//! Число
|
||||
static constexpr std::array<Grammem, 2> ALL_NUMBERS = {
|
||||
Grammem::sing, // единственное
|
||||
Grammem::plur // множественное
|
||||
};
|
||||
|
||||
//! Род
|
||||
static constexpr std::array<Grammem, 3> ALL_GENDERS = {
|
||||
Grammem::masc, // мужской
|
||||
Grammem::femn, // женский
|
||||
Grammem::neut // средний
|
||||
};
|
||||
|
||||
//! Время
|
||||
static constexpr std::array<Grammem, 3> ALL_TENSES = {
|
||||
Grammem::pres, // настоящее
|
||||
Grammem::past, // прошлое
|
||||
Grammem::futr // будущее
|
||||
};
|
||||
|
||||
//! Лицо
|
||||
static constexpr std::array<Grammem, 3> ALL_PERSONS = {
|
||||
Grammem::per1, // первое (я, мы)
|
||||
Grammem::per2, // второе (ты, вы)
|
||||
Grammem::per3 // третье (он, она, оно, они)
|
||||
};
|
||||
|
||||
//! Словоформы терминологической связки
|
||||
static const std::array<Morphology, 12> 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<ccl::lang::Morphology> {
|
||||
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<uint32_t>(tag);
|
||||
}
|
||||
return result + 0xFF * static_cast<uint32_t>(size(form.tags)); // NOLINT
|
||||
}
|
||||
};
|
||||
} // namespace std
|
94
ccl/cclLang/include/ccl/lang/Reference.h
Normal file
94
ccl/cclLang/include/ccl/lang/Reference.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/Strings.hpp"
|
||||
#include "ccl/cclMeta.hpp"
|
||||
#include "ccl/Substitutes.hpp"
|
||||
#include "ccl/lang/EntityTermContext.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
#include <string_view>
|
||||
|
||||
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<std::monostate, EntityRef, CollaborationRef>;
|
||||
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<Reference> 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
|
84
ccl/cclLang/include/ccl/lang/RefsManager.h
Normal file
84
ccl/cclLang/include/ccl/lang/RefsManager.h
Normal file
|
@ -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<Reference> 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<typename RangeIterator>
|
||||
bool UpdatePositions(RangeIterator nextPos);
|
||||
|
||||
//! Erase references in range or at position
|
||||
std::optional<StrRange> 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<Reference>::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<typename RangeIterator>
|
||||
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
|
22
ccl/cclLang/include/ccl/lang/TextEnvironment.h
Normal file
22
ccl/cclLang/include/ccl/lang/TextEnvironment.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/lang/TextProcessor.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ccl::lang {
|
||||
|
||||
class TextEnvironment final {
|
||||
private:
|
||||
std::unique_ptr<TextProcessor> processor{ std::make_unique<TextProcessor>() };
|
||||
|
||||
public:
|
||||
bool skipResolving{ false };
|
||||
|
||||
public:
|
||||
static void SetProcessor(std::unique_ptr<TextProcessor> newProcessor) noexcept;
|
||||
[[nodiscard]] static TextProcessor& Processor() noexcept;
|
||||
[[nodiscard]] static TextEnvironment& Instance() noexcept;
|
||||
};
|
||||
|
||||
} // namespace ccl::lang
|
40
ccl/cclLang/include/ccl/lang/TextProcessor.h
Normal file
40
ccl/cclLang/include/ccl/lang/TextProcessor.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/lang/Morphology.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
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
|
76
ccl/cclLang/src/LexicalTerm.cpp
Normal file
76
ccl/cclLang/src/LexicalTerm.cpp
Normal file
|
@ -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<Morphology, std::string>& 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
|
13
ccl/cclLang/src/Literals.cpp
Normal file
13
ccl/cclLang/src/Literals.cpp
Normal file
|
@ -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
|
58
ccl/cclLang/src/ManagedText.cpp
Normal file
58
ccl/cclLang/src/ManagedText.cpp
Normal file
|
@ -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<std::string> ManagedText::Referals() const {
|
||||
const auto refs = Reference::ExtractAll(rawText);
|
||||
std::unordered_set<std::string> result{};
|
||||
for (const auto& ref : refs) {
|
||||
if (ref.IsEntity()) {
|
||||
result.emplace(ref.GetEntity());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ccl::lang
|
62
ccl/cclLang/src/Morphology.cpp
Normal file
62
ccl/cclLang/src/Morphology.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "ccl/lang/Morphology.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "ccl/Strings.hpp"
|
||||
|
||||
namespace ccl::lang {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename TagsContainer, typename FilterContainer>
|
||||
Grammem ExtractSingleIntersection(const TagsContainer& tags, const FilterContainer& filter) {
|
||||
std::vector<Grammem> 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<std::string_view>& 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
|
214
ccl/cclLang/src/Reference.cpp
Normal file
214
ccl/cclLang/src/Reference.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include "ccl/lang/Reference.h"
|
||||
|
||||
// TODO: Use format library for GCC when available (GCC13+)
|
||||
#if !defined(__GNUC__) && !defined(__clang__)
|
||||
#include <format>
|
||||
#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<std::string_view> 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<std::string_view>& 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<std::string_view>& 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<StrRange>
|
||||
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<int16_t>(stoi(std::string{ tokens.at(CollaborationRef::CR_OFFSET) })) }
|
||||
};
|
||||
}
|
||||
default:
|
||||
case ReferenceType::invalid: return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Reference> Reference::ExtractAll(const std::string_view text) {
|
||||
std::vector<Reference> 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<EntityRef>(data).entity; }
|
||||
const Morphology& Reference::GetForm() const { return std::get<EntityRef>(data).form; }
|
||||
|
||||
bool Reference::TranslateEntity(const StrTranslator& old2New) {
|
||||
auto& refData = std::get<EntityRef>(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<CollaborationRef>(data).offset; }
|
||||
const std::string& Reference::GetNominal() const { return std::get<CollaborationRef>(data).nominal; }
|
||||
|
||||
std::string Reference::ToString() const {
|
||||
switch (type) {
|
||||
case ReferenceType::entity: return std::get<EntityRef>(data).ToString();
|
||||
case ReferenceType::collaboration: return std::get<CollaborationRef>(data).ToString();
|
||||
default:
|
||||
case ReferenceType::invalid: return "";
|
||||
}
|
||||
}
|
||||
|
||||
void Reference::ResolveCollaboration(const Reference* master) {
|
||||
const auto& refData = std::get<CollaborationRef>(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<EntityRef>(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
|
222
ccl/cclLang/src/RefsManager.cpp
Normal file
222
ccl/cclLang/src/RefsManager.cpp
Normal file
|
@ -0,0 +1,222 @@
|
|||
#include "ccl/lang/RefsManager.h"
|
||||
|
||||
#include "ccl/lang/LexicalTerm.h"
|
||||
|
||||
namespace ccl::lang {
|
||||
|
||||
namespace {
|
||||
|
||||
void ShiftAllAfter(std::vector<Reference>& refs, std::vector<Reference>::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<StrRange> 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
|
18
ccl/cclLang/src/TextEnvironment.cpp
Normal file
18
ccl/cclLang/src/TextEnvironment.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "ccl/lang/TextEnvironment.h"
|
||||
|
||||
namespace ccl::lang {
|
||||
|
||||
void TextEnvironment::SetProcessor(std::unique_ptr<TextProcessor> 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
|
55
ccl/cclLang/src/TextProcessor.cpp
Normal file
55
ccl/cclLang/src/TextProcessor.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "ccl/lang/TextProcessor.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
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
|
26
ccl/cclLang/test/CMakeLists.txt
Normal file
26
ccl/cclLang/test/CMakeLists.txt
Normal file
|
@ -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)
|
226
ccl/cclLang/test/cclLangTest.vcxproj
Normal file
226
ccl/cclLang/test/cclLangTest.vcxproj
Normal file
|
@ -0,0 +1,226 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4754356B-DC01-4564-A035-270FFB72F6A0}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<ProjectName>cclLangTest</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<VCToolsVersion />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<VCToolsVersion />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets" Condition="Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>build\x86\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>build\x64\$(Configuration)\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\cclLang.vcxproj">
|
||||
<Project>{76B03803-56CC-47C2-A8F0-2241FCAF2898}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testLexicalTerm.cpp" />
|
||||
<ClCompile Include="src\testManagedText.cpp" />
|
||||
<ClCompile Include="src\testMorphology.cpp" />
|
||||
<ClCompile Include="src\testReference.cpp" />
|
||||
<ClCompile Include="src\testRefsManager.cpp" />
|
||||
<ClCompile Include="src\testTextProcessor.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utils\FakeTermContext.hpp" />
|
||||
<ClInclude Include="utils\FakeTextProcessor.hpp" />
|
||||
<ClInclude Include="utils\MockTextProcessor.hpp" />
|
||||
<ClInclude Include="utils\RefHelper.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>cclLangd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>cclLangd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalDependencies>cclLang.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>utils;..\include;..\header;..\..\cclCommons\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalDependencies>cclLang.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\output\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>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}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
48
ccl/cclLang/test/cclLangTest.vcxproj.filters
Normal file
48
ccl/cclLang/test/cclLangTest.vcxproj.filters
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{ed04b33d-515f-46b0-aad1-54dcbc55a5fd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="utils">
|
||||
<UniqueIdentifier>{e557a0c7-3116-47e0-9713-487c7e6cc101}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\testManagedText.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testReference.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testRefsManager.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testLexicalTerm.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testTextProcessor.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\testMorphology.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utils\FakeTextProcessor.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils\FakeTermContext.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils\RefHelper.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils\MockTextProcessor.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
4
ccl/cclLang/test/packages.config
Normal file
4
ccl/cclLang/test/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.7" targetFramework="native" />
|
||||
</packages>
|
132
ccl/cclLang/test/src/testLexicalTerm.cpp
Normal file
132
ccl/cclLang/test/src/testLexicalTerm.cpp
Normal file
|
@ -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<ccl::lang::TextProcessor>());
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
129
ccl/cclLang/test/src/testManagedText.cpp
Normal file
129
ccl/cclLang/test/src/testManagedText.cpp
Normal file
|
@ -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<std::string> 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<std::string>({ "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"));
|
||||
}
|
||||
}
|
107
ccl/cclLang/test/src/testMorphology.cpp
Normal file
107
ccl/cclLang/test/src/testMorphology.cpp
Normal file
|
@ -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");
|
||||
}
|
278
ccl/cclLang/test/src/testReference.cpp
Normal file
278
ccl/cclLang/test/src/testReference.cpp
Normal file
|
@ -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<tccl::MockTextProcessor>());
|
||||
auto& processor = static_cast<tccl::MockTextProcessor&>(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<TextProcessor>());
|
||||
}
|
||||
|
||||
TEST_F(UTReference, ResolveCollaborationEmpty) {
|
||||
TextEnvironment::SetProcessor(std::make_unique<tccl::MockTextProcessor>());
|
||||
auto& processor = static_cast<tccl::MockTextProcessor&>(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<TextProcessor>());
|
||||
}
|
||||
|
||||
TEST_F(UTReference, ResolveCollaborationValid) {
|
||||
TextEnvironment::SetProcessor(std::make_unique<tccl::MockTextProcessor>());
|
||||
auto& processor = static_cast<tccl::MockTextProcessor&>(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<TextProcessor>());
|
||||
}
|
304
ccl/cclLang/test/src/testRefsManager.cpp
Normal file
304
ccl/cclLang/test/src/testRefsManager.cpp
Normal file
|
@ -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<StrRange> ranges;
|
||||
|
||||
FakeUpdater(std::vector<StrRange> ranges)
|
||||
: ranges{ std::move(ranges) } {}
|
||||
|
||||
std::optional<StrRange> 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<tccl::MockTextProcessor>());
|
||||
auto& processor = static_cast<tccl::MockTextProcessor&>(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<TextProcessor>());
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
38
ccl/cclLang/test/src/testTextProcessor.cpp
Normal file
38
ccl/cclLang/test/src/testTextProcessor.cpp
Normal file
|
@ -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"));
|
||||
}
|
12
ccl/cclLang/test/unity/cclLangTest.cpp
Normal file
12
ccl/cclLang/test/unity/cclLangTest.cpp
Normal file
|
@ -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"
|
25
ccl/cclLang/test/utils/FakeTermContext.hpp
Normal file
25
ccl/cclLang/test/utils/FakeTermContext.hpp
Normal file
|
@ -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<std::string, ccl::lang::LexicalTerm> 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);
|
||||
}
|
||||
}
|
||||
};
|
8
ccl/cclLang/test/utils/FakeTextProcessor.hpp
Normal file
8
ccl/cclLang/test/utils/FakeTextProcessor.hpp
Normal file
|
@ -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})";
|
||||
|
||||
};
|
91
ccl/cclLang/test/utils/MockTextProcessor.hpp
Normal file
91
ccl/cclLang/test/utils/MockTextProcessor.hpp
Normal file
|
@ -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<Morphology> form{};
|
||||
std::optional<std::string> mainText{};
|
||||
};
|
||||
|
||||
using InflectDB = std::vector<std::pair<std::pair<std::string, Morphology>, std::string>>;
|
||||
using DependantDB = std::vector<std::pair<std::pair<std::string, std::string>, std::string>>;
|
||||
|
||||
mutable std::vector<CallEntry> 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::string, Morphology>(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::string, std::string>(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
|
13
ccl/cclLang/test/utils/RefHelper.hpp
Normal file
13
ccl/cclLang/test/utils/RefHelper.hpp
Normal file
|
@ -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
|
10
ccl/cclLang/unity/cclLang.cpp
Normal file
10
ccl/cclLang/unity/cclLang.cpp
Normal file
|
@ -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"
|
70
ccl/cmake/CXXTargets.cmake
Normal file
70
ccl/cmake/CXXTargets.cmake
Normal file
|
@ -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()
|
9
ccl/conanfile.txt
Normal file
9
ccl/conanfile.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
[requires]
|
||||
gtest/1.14.0
|
||||
|
||||
[generators]
|
||||
CMakeDeps
|
||||
CMakeToolchain
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
259
ccl/core/ConceptLibrary.vcxproj
Normal file
259
ccl/core/ConceptLibrary.vcxproj
Normal file
|
@ -0,0 +1,259 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{B0ABA27B-9D39-4B48-9977-AFF20925B309}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<RootNamespace>ConceptLibrary</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>ConceptCoreLibrary</ProjectName>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>..\..\output\lib\x86\</OutDir>
|
||||
<IntDir>build\x86\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)d</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>..\..\output\lib\x64\</OutDir>
|
||||
<IntDir>build\x64\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<ProgramDataBaseFileName>$(OutDir)$(ProjectName).pdb</ProgramDataBaseFileName>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<ProgramDataBaseFileName>$(OutDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<SupportJustMyCode>true</SupportJustMyCode>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(OutDir)$(ProjectName)d.pdb</ProgramDataBaseFileName>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>include;header;..\RSlang\include;..\cclGraph\include;..\cclCommons\include;..\cclLang\include</AdditionalIncludeDirectories>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(OutDir)$(ProjectName).pdb</ProgramDataBaseFileName>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /s /q /i include ..\..\output\include</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\api\RSFormJA.cpp" />
|
||||
<ClCompile Include="src\env\cclEnvironment.cpp" />
|
||||
<ClCompile Include="src\JSON.cpp" />
|
||||
<ClCompile Include="src\ops\EquationOptions.cpp" />
|
||||
<ClCompile Include="src\ops\RSAggregator.cpp" />
|
||||
<ClCompile Include="src\ops\RSEquationProcessor.cpp" />
|
||||
<ClCompile Include="src\ops\RSOperations.cpp" />
|
||||
<ClCompile Include="src\oss\OSSchema.cpp" />
|
||||
<ClCompile Include="src\oss\ossGraphFacet.cpp" />
|
||||
<ClCompile Include="src\oss\ossGridFacet.cpp" />
|
||||
<ClCompile Include="src\oss\ossOperationsFacet.cpp" />
|
||||
<ClCompile Include="src\oss\ossSourceFacet.cpp" />
|
||||
<ClCompile Include="src\oss\RSSynthesProcessor.cpp" />
|
||||
<ClCompile Include="src\semantic\rscore\ConceptRecord.cpp" />
|
||||
<ClCompile Include="src\semantic\rscore\CstList.cpp" />
|
||||
<ClCompile Include="src\semantic\rscore\IdentityManager.cpp" />
|
||||
<ClCompile Include="src\semantic\rscore\RSCore.cpp" />
|
||||
<ClCompile Include="src\semantic\rsform\RSForm.cpp" />
|
||||
<ClCompile Include="src\semantic\rsform\rsModificationFacet.cpp" />
|
||||
<ClCompile Include="src\semantic\rsform\rsOperationFacet.cpp" />
|
||||
<ClCompile Include="src\semantic\rsmodel\InterpretationStorage.cpp" />
|
||||
<ClCompile Include="src\semantic\rsmodel\rsCalculationFacet.cpp" />
|
||||
<ClCompile Include="src\semantic\rsmodel\RSModel.cpp" />
|
||||
<ClCompile Include="src\semantic\rsmodel\rsValuesFacet.cpp" />
|
||||
<ClCompile Include="src\semantic\schema\RSConcept.cpp" />
|
||||
<ClCompile Include="src\semantic\schema\Schema.cpp" />
|
||||
<ClCompile Include="src\semantic\thesaurus\TextConcept.cpp" />
|
||||
<ClCompile Include="src\semantic\thesaurus\Thesaurus.cpp" />
|
||||
<ClCompile Include="src\tools\CstNameGenerator.cpp" />
|
||||
<ClCompile Include="src\tools\EntityGenerator.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\api\RSFormJA.h" />
|
||||
<ClInclude Include="include\ccl\env\cclEnvironment.h" />
|
||||
<ClInclude Include="include\ccl\env\SourceManager.hpp" />
|
||||
<ClInclude Include="include\ccl\Operation.hpp" />
|
||||
<ClInclude Include="include\ccl\ops\EquationOptions.h" />
|
||||
<ClInclude Include="include\ccl\ops\RSAggregator.h" />
|
||||
<ClInclude Include="include\ccl\ops\RSEquationProcessor.h" />
|
||||
<ClInclude Include="include\ccl\ops\RSOperations.h" />
|
||||
<ClInclude Include="include\ccl\oss\OperationProcessor.hpp" />
|
||||
<ClInclude Include="include\ccl\oss\OSSchema.h" />
|
||||
<ClInclude Include="include\ccl\oss\ossGraphFacet.h" />
|
||||
<ClInclude Include="include\ccl\oss\ossGridFacet.h" />
|
||||
<ClInclude Include="include\ccl\oss\ossOperationsFacet.h" />
|
||||
<ClInclude Include="include\ccl\oss\ossSourceFacet.h" />
|
||||
<ClInclude Include="include\ccl\oss\Pict.hpp" />
|
||||
<ClInclude Include="include\ccl\oss\RSSynthesProcessor.h" />
|
||||
<ClInclude Include="include\ccl\semantic\ConceptRecord.h" />
|
||||
<ClInclude Include="include\ccl\semantic\CstFilters.hpp" />
|
||||
<ClInclude Include="include\ccl\semantic\CstList.h" />
|
||||
<ClInclude Include="include\ccl\semantic\CstType.hpp" />
|
||||
<ClInclude Include="include\ccl\semantic\IdentityManager.h" />
|
||||
<ClInclude Include="include\ccl\semantic\InterpretationStorage.h" />
|
||||
<ClInclude Include="include\ccl\semantic\rsCalculationFacet.h" />
|
||||
<ClInclude Include="include\ccl\semantic\RSConcept.h" />
|
||||
<ClInclude Include="include\ccl\semantic\RSCore.h" />
|
||||
<ClInclude Include="include\ccl\semantic\RSForm.h" />
|
||||
<ClInclude Include="include\ccl\semantic\RSModel.h" />
|
||||
<ClInclude Include="include\ccl\semantic\rsModificationFacet.h" />
|
||||
<ClInclude Include="include\ccl\semantic\rsOperationFacet.h" />
|
||||
<ClInclude Include="include\ccl\semantic\rsValuesFacet.h" />
|
||||
<ClInclude Include="include\ccl\semantic\Schema.h" />
|
||||
<ClInclude Include="include\ccl\semantic\TextConcept.h" />
|
||||
<ClInclude Include="include\ccl\semantic\TextData.hpp" />
|
||||
<ClInclude Include="include\ccl\semantic\Thesaurus.h" />
|
||||
<ClInclude Include="include\ccl\Source.hpp" />
|
||||
<ClInclude Include="include\ccl\tools\CstNameGenerator.h" />
|
||||
<ClInclude Include="include\ccl\tools\EntityGenerator.h" />
|
||||
<ClInclude Include="include\ccl\tools\EnumJSON.hpp" />
|
||||
<ClInclude Include="include\ccl\tools\JSON.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\cclGraph\cclGraph.vcxproj">
|
||||
<Project>{7e1d5338-f819-4c96-b461-9eaab8d02e1d}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\cclLang\cclLang.vcxproj">
|
||||
<Project>{76b03803-56cc-47c2-a8f0-2241fcaf2898}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RSlang\RSlang.vcxproj">
|
||||
<Project>{a8529c63-42f5-43e6-97b8-2ec83f23e1f9}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
252
ccl/core/ConceptLibrary.vcxproj.filters
Normal file
252
ccl/core/ConceptLibrary.vcxproj.filters
Normal file
|
@ -0,0 +1,252 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="02 env">
|
||||
<UniqueIdentifier>{86d3c4ce-8b73-446b-ae23-3c51e5321065}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="01 tools">
|
||||
<UniqueIdentifier>{bb109e85-4730-40c3-8cf6-4cf4a3c7111d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic">
|
||||
<UniqueIdentifier>{afefed49-4a72-4a1d-87f0-26c3b8f3f1e9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="04 ops">
|
||||
<UniqueIdentifier>{5c6e9f8c-3112-47da-9118-ecfbaa836009}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="05 oss">
|
||||
<UniqueIdentifier>{dafdb290-2760-4574-bf2e-86b94008efe7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic\03 RSCore">
|
||||
<UniqueIdentifier>{1d5f943e-0673-47a8-b4ab-ef179e4c3dd1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic\04 RSForm">
|
||||
<UniqueIdentifier>{2bd129f8-604d-4b83-affd-8f322bbff657}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic\05 RSModel">
|
||||
<UniqueIdentifier>{5de97bf2-566e-46c1-9b21-9ceacac19749}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic\01 Schema">
|
||||
<UniqueIdentifier>{0a673bb0-fb75-4cc4-8fd7-1b1d033a699a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="03 semantic\02 Thesaurus">
|
||||
<UniqueIdentifier>{166b33ed-84a5-4040-8398-983a541cc3db}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="04 ops\01 RSOps">
|
||||
<UniqueIdentifier>{3b955deb-294b-4000-bb01-4a043fdfbf38}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="06 API">
|
||||
<UniqueIdentifier>{b2207c2a-30f0-424c-bfe2-f81eeca2949d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\env\cclEnvironment.cpp">
|
||||
<Filter>02 env</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\EntityGenerator.cpp">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\CstNameGenerator.cpp">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ops\RSAggregator.cpp">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ops\RSOperations.cpp">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\ossGraphFacet.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\ossGridFacet.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\ossOperationsFacet.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\ossSourceFacet.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\RSSynthesProcessor.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\oss\OSSchema.cpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ops\EquationOptions.cpp">
|
||||
<Filter>04 ops</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ops\RSEquationProcessor.cpp">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\JSON.cpp">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsform\RSForm.cpp">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsform\rsModificationFacet.cpp">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsmodel\InterpretationStorage.cpp">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsmodel\rsCalculationFacet.cpp">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsmodel\RSModel.cpp">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsmodel\rsValuesFacet.cpp">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rsform\rsOperationFacet.cpp">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rscore\RSCore.cpp">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rscore\ConceptRecord.cpp">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rscore\CstList.cpp">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\schema\RSConcept.cpp">
|
||||
<Filter>03 semantic\01 Schema</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\schema\Schema.cpp">
|
||||
<Filter>03 semantic\01 Schema</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\thesaurus\TextConcept.cpp">
|
||||
<Filter>03 semantic\02 Thesaurus</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\thesaurus\Thesaurus.cpp">
|
||||
<Filter>03 semantic\02 Thesaurus</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\semantic\rscore\IdentityManager.cpp">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\api\RSFormJA.cpp">
|
||||
<Filter>06 API</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ccl\env\SourceManager.hpp">
|
||||
<Filter>02 env</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\env\cclEnvironment.h">
|
||||
<Filter>02 env</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\tools\EntityGenerator.h">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\tools\CstNameGenerator.h">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\ops\RSAggregator.h">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\ops\RSOperations.h">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\OSSchema.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\ossGraphFacet.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\ossGridFacet.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\ossOperationsFacet.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\ossSourceFacet.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\Pict.hpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\OperationProcessor.hpp">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\oss\RSSynthesProcessor.h">
|
||||
<Filter>05 oss</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\ops\EquationOptions.h">
|
||||
<Filter>04 ops</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\tools\JSON.h">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\tools\EnumJSON.hpp">
|
||||
<Filter>01 tools</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\Operation.hpp">
|
||||
<Filter>03 semantic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\Source.hpp">
|
||||
<Filter>03 semantic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\RSForm.h">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\rsModificationFacet.h">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\rsOperationFacet.h">
|
||||
<Filter>03 semantic\04 RSForm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\InterpretationStorage.h">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\rsCalculationFacet.h">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\RSModel.h">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\rsValuesFacet.h">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\TextData.hpp">
|
||||
<Filter>03 semantic\05 RSModel</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\RSCore.h">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\TextConcept.h">
|
||||
<Filter>03 semantic\02 Thesaurus</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\RSConcept.h">
|
||||
<Filter>03 semantic\01 Schema</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\Schema.h">
|
||||
<Filter>03 semantic\01 Schema</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\Thesaurus.h">
|
||||
<Filter>03 semantic\02 Thesaurus</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\CstList.h">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\CstFilters.hpp">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\ConceptRecord.h">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\CstType.hpp">
|
||||
<Filter>03 semantic\01 Schema</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\semantic\IdentityManager.h">
|
||||
<Filter>03 semantic\03 RSCore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\ops\RSEquationProcessor.h">
|
||||
<Filter>04 ops\01 RSOps</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ccl\api\RSFormJA.h">
|
||||
<Filter>06 API</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
3
ccl/core/RunCoverage.bat
Normal file
3
ccl/core/RunCoverage.bat
Normal file
|
@ -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
|
85
ccl/core/include/ccl/Operation.hpp
Normal file
85
ccl/core/include/ccl/Operation.hpp
Normal file
|
@ -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<EntityTranslation>;
|
||||
|
||||
using Args = std::vector<const src::DataStream*>;
|
||||
using ArgsInfo = std::vector<src::DataType>;
|
||||
|
||||
//! 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<src::DataStream> value{ nullptr };
|
||||
meta::UniqueCPPtr<TranslationData> translation{ nullptr };
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
} // namespace ccl::ops
|
196
ccl/core/include/ccl/Source.hpp
Normal file
196
ccl/core/include/ccl/Source.hpp
Normal file
|
@ -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<std::is_base_of_v<DataStream, T>>
|
||||
>
|
||||
const T* CastData(const DataStream* data) noexcept {
|
||||
return dynamic_cast<const T*>(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<DataStream> /*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<SourceCallback*> 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<uint8_t>(result) < static_cast<uint8_t>(curStatus)) {
|
||||
result = curStatus;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
} // namespace ccl::src
|
30
ccl/core/include/ccl/api/RSFormJA.h
Normal file
30
ccl/core/include/ccl/api/RSFormJA.h
Normal file
|
@ -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<semantic::RSForm> 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
|
80
ccl/core/include/ccl/env/SourceManager.hpp
vendored
Normal file
80
ccl/core/include/ccl/env/SourceManager.hpp
vendored
Normal file
|
@ -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
|
24
ccl/core/include/ccl/env/cclEnvironment.h
vendored
Normal file
24
ccl/core/include/ccl/env/cclEnvironment.h
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "ccl/env/SourceManager.hpp"
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace ccl {
|
||||
|
||||
//! Enivroment configuration - !Global state!
|
||||
class Environment final {
|
||||
std::unique_ptr<SourceManager> sources{ std::make_unique<SourceManager>() };
|
||||
|
||||
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<SourceManager> newSources);
|
||||
};
|
||||
|
||||
} // namespace ccl
|
67
ccl/core/include/ccl/ops/EquationOptions.h
Normal file
67
ccl/core/include/ccl/ops/EquationOptions.h
Normal file
|
@ -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<EntityUID, Equation>;
|
||||
|
||||
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
|
33
ccl/core/include/ccl/ops/RSAggregator.h
Normal file
33
ccl/core/include/ccl/ops/RSAggregator.h
Normal file
|
@ -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<EntityTranslation> Merge(const semantic::RSForm& previous, const EntityTranslation& oldToNew);
|
||||
|
||||
private:
|
||||
void Clear() noexcept;
|
||||
bool PrepareSubstitutes();
|
||||
void TransferNew();
|
||||
void TransferIheritedData();
|
||||
void UpdateReferences();
|
||||
|
||||
[[nodiscard]] std::optional<EntityUID> TransferCst(EntityUID target, semantic::ListIterator insertWhere);
|
||||
};
|
||||
|
||||
} // namespace ccl::ops
|
44
ccl/core/include/ccl/ops/RSEquationProcessor.h
Normal file
44
ccl/core/include/ccl/ops/RSEquationProcessor.h
Normal file
|
@ -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
|
116
ccl/core/include/ccl/ops/RSOperations.h
Normal file
116
ccl/core/include/ccl/ops/RSOperations.h
Normal file
|
@ -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<semantic::RSForm> resultSchema{ nullptr };
|
||||
TranslationData translations{};
|
||||
|
||||
public:
|
||||
BinarySynthes(const semantic::RSForm& ks1, const semantic::RSForm& ks2, EquationOptions equations);
|
||||
|
||||
public:
|
||||
std::unique_ptr<semantic::RSForm> 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<semantic::RSForm> 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<semantic::RSForm> 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<semantic::RSForm> resultSchema{ nullptr };
|
||||
|
||||
SetOfEntities ignoreResult{};
|
||||
EntityUID baseCst;
|
||||
std::string baseStr{};
|
||||
|
||||
VectorOfEntities processOrder{};
|
||||
std::string baseID{};
|
||||
std::string termID{};
|
||||
std::unordered_map<EntityUID, std::string> types{};
|
||||
std::unordered_set<std::string> moifiedFuncs{};
|
||||
StrSubstitutes substitutes{};
|
||||
|
||||
public:
|
||||
OpRelativation(const semantic::RSForm& ks, EntityUID target, const SetOfEntities& ignore = {});
|
||||
|
||||
public:
|
||||
std::unique_ptr<semantic::RSForm> 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
|
137
ccl/core/include/ccl/oss/OSSchema.h
Normal file
137
ccl/core/include/ccl/oss/OSSchema.h
Normal file
|
@ -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<PictID, Pict>;
|
||||
Storage storage{};
|
||||
tools::EntityGenerator idGen{};
|
||||
|
||||
std::unique_ptr<ossGridFacet> grid;
|
||||
std::unique_ptr<ossGraphFacet> graph;
|
||||
std::unique_ptr<ossSourceFacet> sources;
|
||||
std::unique_ptr<ossOperationsFacet> ops;
|
||||
|
||||
class Callback;
|
||||
std::unique_ptr<Callback> 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<OperationHandle> params);
|
||||
|
||||
private:
|
||||
Pict* Access(PictID pid);
|
||||
void InsertInternal(const Pict& pict, GridPosition pos,
|
||||
const src::Handle& srcHandle,
|
||||
std::unique_ptr<OperationHandle> 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
|
45
ccl/core/include/ccl/oss/OperationProcessor.hpp
Normal file
45
ccl/core/include/ccl/oss/OperationProcessor.hpp
Normal file
|
@ -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<src::DataType>
|
||||
ResultingTypeFor(ops::Type /*operation*/, const ops::ArgsInfo& /*args*/) const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool CheckCall(const ops::Call& /*call*/) const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::optional<ops::Result> 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
|
43
ccl/core/include/ccl/oss/Pict.hpp
Normal file
43
ccl/core/include/ccl/oss/Pict.hpp
Normal file
|
@ -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
|
27
ccl/core/include/ccl/oss/RSSynthesProcessor.h
Normal file
27
ccl/core/include/ccl/oss/RSSynthesProcessor.h
Normal file
|
@ -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<src::DataType>
|
||||
ResultingTypeFor(ops::Type /*operation*/,
|
||||
const ops::ArgsInfo& args) const override;
|
||||
|
||||
[[nodiscard]] bool CheckCall(const ops::Call& call) const override;
|
||||
|
||||
[[nodiscard]] std::optional<ops::Result>
|
||||
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
|
44
ccl/core/include/ccl/oss/ossGraphFacet.h
Normal file
44
ccl/core/include/ccl/oss/ossGraphFacet.h
Normal file
|
@ -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<OSSchema> {
|
||||
friend class OSSchema;
|
||||
|
||||
using AdjacencyList = std::vector<std::vector<size_t>>;
|
||||
AdjacencyList graph{};
|
||||
std::vector<PictID> items{};
|
||||
|
||||
public:
|
||||
explicit ossGraphFacet(const OSSchema& core) noexcept
|
||||
: ConstFacet<OSSchema>(core) {}
|
||||
|
||||
public:
|
||||
[[nodiscard]] std::vector<PictID> ParentsOf(PictID pid) const;
|
||||
[[nodiscard]] std::vector<PictID> ChildrenOf(PictID pid) const;
|
||||
[[nodiscard]] std::optional<size_t> ParentIndex(PictID parent, PictID child) const;
|
||||
|
||||
[[nodiscard]] std::vector<std::pair<PictID, PictID>> EdgeList() const;
|
||||
|
||||
[[nodiscard]] std::vector<PictID> ExecuteOrder() const;
|
||||
|
||||
// Note: use only for Serialization!
|
||||
bool LoadParent(PictID child, PictID parent);
|
||||
|
||||
private:
|
||||
void AddItem(PictID item, const std::vector<PictID>& connectedItems);
|
||||
void Erase(PictID item);
|
||||
|
||||
size_t InsertKeyValue(PictID item);
|
||||
[[nodiscard]] size_t Item2ID(PictID item);
|
||||
[[nodiscard]] std::vector<size_t> Item2ID(const std::vector<PictID>& input);
|
||||
[[nodiscard]] std::optional<size_t> FindItemIndex(PictID item) const;
|
||||
[[nodiscard]] std::vector<PictID> Index2PIDs(const std::vector<size_t>& input) const;
|
||||
};
|
||||
|
||||
} // namespace ccl::oss
|
83
ccl/core/include/ccl/oss/ossGridFacet.h
Normal file
83
ccl/core/include/ccl/oss/ossGridFacet.h
Normal file
|
@ -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<ccl::oss::GridPosition> {
|
||||
uint32_t operator()(const ccl::oss::GridPosition& k) const noexcept {
|
||||
using std::hash;
|
||||
return static_cast<uint32_t>(hash<int32_t>()(k.row) ^ (hash<int32_t>()(k.column) << 1U));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace ccl::oss {
|
||||
|
||||
using Grid = std::unordered_map<GridPosition, PictID>;
|
||||
|
||||
//! OSS grid positions facet
|
||||
class ossGridFacet final : public meta::MutatorFacet<OSSchema> {
|
||||
friend class OSSchema;
|
||||
|
||||
Grid grid{};
|
||||
|
||||
public:
|
||||
static constexpr GridPosition origin{ 0, 0 };
|
||||
|
||||
public:
|
||||
explicit ossGridFacet(OSSchema& oss) noexcept // NOLINT(bugprone-exception-escape)
|
||||
: MutatorFacet<OSSchema>(oss) {}
|
||||
|
||||
public:
|
||||
[[nodiscard]] const Grid& data() const noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<PictID> operator()(GridPosition pos) const;
|
||||
[[nodiscard]] std::optional<GridPosition> 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
|
87
ccl/core/include/ccl/oss/ossOperationsFacet.h
Normal file
87
ccl/core/include/ccl/oss/ossOperationsFacet.h
Normal file
|
@ -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<ops::Options> options{ nullptr };
|
||||
meta::UniqueCPPtr<ops::TranslationData> translations{ nullptr };
|
||||
|
||||
bool broken{ false };
|
||||
bool outdated{ false };
|
||||
|
||||
void Reset() noexcept;
|
||||
void InitOperation(ops::Type operation,
|
||||
meta::UniqueCPPtr<ops::Options> newOptions) noexcept;
|
||||
};
|
||||
|
||||
//! OSS operations facet
|
||||
class ossOperationsFacet final : public meta::MutatorFacet<OSSchema> {
|
||||
friend class OSSchema;
|
||||
|
||||
public:
|
||||
std::string ossPath{};
|
||||
|
||||
private:
|
||||
using Operations = std::unordered_map<PictID, std::unique_ptr<OperationHandle>>;
|
||||
using Processors = std::vector<std::unique_ptr<OperationsProcessor>>;
|
||||
using ProcessorMapping = std::unordered_map<ops::Type, OperationsProcessor*>;
|
||||
|
||||
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<ops::Type> VariantsFor(PictID pid) const;
|
||||
[[nodiscard]] bool IsExecutable(PictID pid);
|
||||
[[nodiscard]] bool IsTranslatable(PictID pid);
|
||||
|
||||
bool InitFor(PictID pid, ops::Type operation,
|
||||
std::unique_ptr<ops::Options> 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<EntityTranslation> 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
|
79
ccl/core/include/ccl/oss/ossSourceFacet.h
Normal file
79
ccl/core/include/ccl/oss/ossSourceFacet.h
Normal file
|
@ -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<OSSchema> {
|
||||
friend class OSSchema;
|
||||
friend class ossOperationsFacet;
|
||||
|
||||
public:
|
||||
std::u8string ossDomain{};
|
||||
|
||||
private:
|
||||
using Container = std::unordered_map<PictID, src::Handle>;
|
||||
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<PictID> 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<src::DataStream> 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<src::DataStream::ValueType>
|
||||
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
|
31
ccl/core/include/ccl/semantic/ConceptRecord.h
Normal file
31
ccl/core/include/ccl/semantic/ConceptRecord.h
Normal file
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user