From cb460a67097e32190267efbd2ef1d1b90c88afdf Mon Sep 17 00:00:00 2001 From: BELLIER Sacha Date: Sun, 21 Apr 2024 20:59:49 +0200 Subject: [PATCH] merge with previous version --- .bazelrc | 17 + .bazelversion | 0 .buildbuddy/workspace_status.bat | 2 + .buildbuddy/workspace_status.ps1 | 33 ++ .buildbuddy/workspace_status.sh | 31 ++ .buildkite/linux_amd64.yml | 17 + .buildkite/pipeline.yml | 5 + .buildkite/template.yml | 4 + .buildkite/windows_amd64.yml | 10 + .github/workflows/ProjectCore.yml | 64 +++ .gitignore | 31 ++ BUILD | 22 + LICENSE | 21 + MODULE.bazel | 10 + Tests/FMT/BaseFMTTests.h | 5 + Tests/FMT/ComplexPattern.cpp | 15 + Tests/FMT/Globber.cpp | 73 +++ Tests/FMT/Index.cpp | 12 + Tests/FMT/Limits.cpp | 115 +++++ Tests/FMT/Shift.cpp | 329 ++++++++++++ Tests/FMT/Specifier.cpp | 28 + Tests/FMT/TextProperties.cpp | 97 ++++ Tests/Tests.cpp | 8 + WORKSPACE | 1 + buildbuddy.yaml | 18 + premake5.lua | 62 +++ src/ProjectCore/Core/Core.h | 32 ++ .../FMT/Context/BasicContext/BasicContext.h | 125 +++++ .../BasicContext/BasicContextCoreImpl.h | 97 ++++ .../BasicContext/BasicContextInclude.h | 5 + .../BasicContext/BasicContextParseImpl.h | 260 ++++++++++ .../BasicContext/ITextPropertiesExecutor.h | 99 ++++ .../BasicContext/TextPropertiesParser.h | 168 ++++++ .../BasicContext/TextPropertiesParserImpl.h | 357 +++++++++++++ .../Utils/BasicContextArgsTupleInterface.h | 106 ++++ .../BasicContext/Utils/FMTContextTemplate.h | 63 +++ .../BaseFormatter/BaseFormat.h | 372 ++++++++++++++ .../BaseFormatter/FormatChrono.h | 172 +++++++ .../BaseFormatter/FormatSTDLib.h | 67 +++ .../BaseFormatter/FormatTextPropertiesColor.h | 87 ++++ .../BaseFormatter/FormatTextPropertiesFront.h | 22 + .../BaseFormatter/FormatTextPropertiesStyle.h | 118 +++++ .../BaseFormatter/FormatterForwarders.h | 102 ++++ .../FormatterContext/BasicFormatterContext.h | 174 +++++++ .../BasicFormatterContextCoreImpl.h | 46 ++ .../BasicFormatterContextParseImpl.h | 45 ++ .../FormatterContextArgsTuple.h | 183 +++++++ .../FormatterANSITextPropertiesExecutor.h | 52 ++ .../FormatterNOTextPropertiesExecutor.h | 52 ++ .../IFormatterTextPropertiesExecutor.h | 20 + .../Context/FormatterContext/FormatterType.h | 50 ++ .../FormatterContext/UtilityFunctions.h | 223 ++++++++ .../FormatterContext/Utils/IndexArgs.h | 32 ++ .../FormatterContext/Utils/NamedArgs.h | 97 ++++ .../FormatterContext/Utils/STDEnumerable.h | 100 ++++ .../ParserContext/BaseParse/BaseParser.h | 307 +++++++++++ .../ParserContext/BaseParse/ParseChrono.h | 14 + .../ParserContext/BaseParse/ParseSTDLib.h | 12 + .../BaseParse/ParseTextPropertiesColor.h | 87 ++++ .../BaseParse/ParseTextPropertiesFront.h | 22 + .../BaseParse/ParseTextPropertiesStyle.h | 118 +++++ .../BaseParse/ParserForwarders.h | 80 +++ .../ParserContext/BasicParserContext.h | 175 +++++++ .../BasicParserContextCoreImpl.h | 41 ++ .../BasicParserContextParseImpl.h | 24 + .../ParserContext/ParserContextArgsTuple.h | 180 +++++++ .../IParserTextPropertiesExecutor.h | 20 + .../ParserANSITextPropertiesExecutor.h | 52 ++ .../ParserNOTextPropertiesExecutor.h | 52 ++ .../FMT/Context/ParserContext/ParserType.h | 36 ++ .../Context/ParserContext/UtilityFunctions.h | 25 + .../FMT/Detail/Buffer/BasicBuffer.h | 113 ++++ .../Buffer/BasicBufferIn/BasicBufferIn.h | 352 +++++++++++++ .../FMT/Detail/Buffer/BasicBufferIn/Integer.h | 79 +++ .../FMT/Detail/Buffer/BasicBufferIn/String.h | 43 ++ .../Buffer/BasicBufferOut/BasicBufferOut.h | 230 +++++++++ .../Detail/Buffer/BasicBufferOut/Integer.h | 167 ++++++ .../Detail/Buffer/BasicBufferOut/Internal.h | 27 + .../FMT/Detail/Buffer/BasicBufferOut/String.h | 17 + .../BufferInProperties/BufferInProperties.h | 32 ++ .../BufferOutManager/BasicBufferOutManager.h | 44 ++ .../DynamicBufferOutManager.h | 110 ++++ .../BufferOutManager/GivenBufferOutManager.h | 36 ++ .../BufferOutManager/StaticBufferOutManager.h | 24 + .../Detail/Buffer/FMTBufferIn/FMTBufferIn.h | 202 ++++++++ .../Buffer/FMTBufferIn/FromFormatData.h | 58 +++ .../FMT/Detail/Buffer/FMTBufferIn/Integer.h | 208 ++++++++ .../FMT/Detail/Buffer/FMTBufferIn/String.h | 15 + .../Detail/Buffer/FMTBufferOut/FMTBufferOut.h | 205 ++++++++ .../Buffer/FMTBufferOut/FromFormatData.h | 58 +++ .../FMT/Detail/Buffer/FMTBufferOut/Integer.h | 244 +++++++++ .../FMT/Detail/Buffer/FMTBufferOut/String.h | 52 ++ .../Buffer/FMTFormatBuffer/FMTFormatBuffer.h | 205 ++++++++ .../FMT/Detail/Buffer/Utils/BufferUtils.h | 73 +++ .../Buffer/Utils/PatternMatching/Glob/Glob.h | 108 ++++ src/ProjectCore/FMT/Detail/Detail.h | 45 ++ src/ProjectCore/FMT/Detail/Exception.h | 28 + .../FormatterHandler/FormatterHandler.h | 29 ++ src/ProjectCore/FMT/Detail/Forwarders.h | 13 + src/ProjectCore/FMT/Detail/IndentHandlers.h | 112 ++++ src/ProjectCore/FMT/Detail/Specifiers.h | 379 ++++++++++++++ .../TextProperties/BaseTextProperties.h | 19 + .../Detail/TextProperties/TextProperties.h | 20 + .../TextProperties/TextPropertiesColor.h | 485 ++++++++++++++++++ .../TextProperties/TextPropertiesFront.h | 60 +++ .../TextProperties/TextPropertiesStyle.h | 257 ++++++++++ src/ProjectCore/FMT/Detail/Types/Types.h | 214 ++++++++ src/ProjectCore/FMT/Detail/Types/TypesInfo.h | 12 + .../FMT/Detail/Types/TypesTraits.h | 76 +++ .../FMT/Detail/UtilsContextsFunctions.h | 22 + src/ProjectCore/FMT/FMT.h | 10 + src/ProjectCore/FMT/Format/CompilationData.h | 78 +++ .../FMT/Format/STDContainer/FMT_array.h | 15 + .../FMT/Format/STDContainer/FMT_deque.h | 15 + .../Format/STDContainer/FMT_forward_list.h | 15 + .../FMT/Format/STDContainer/FMT_list.h | 15 + .../FMT/Format/STDContainer/FMT_map.h | 25 + .../FMT/Format/STDContainer/FMT_queue.h | 14 + .../FMT/Format/STDContainer/FMT_set.h | 23 + .../FMT/Format/STDContainer/FMT_stack.h | 16 + .../FMT/Format/STDContainer/FMT_tuple.h | 57 ++ .../Format/STDContainer/FMT_unordered_map.h | 25 + .../Format/STDContainer/FMT_unordered_set.h | 23 + .../FMT/Format/STDContainer/FMT_vector.h | 15 + .../ProfilerManger/AllEvents.h | 38 ++ .../Instrumentation/ProfilerManger/Detail.h | 11 + .../Instrumentation/ProfilerManger/Event.h | 136 +++++ .../ProfilerManger/EventData.h | 33 ++ .../Instrumentation/ProfilerManger/GetPid.cpp | 25 + .../Instrumentation/ProfilerManger/Profiler.h | 41 ++ .../ProfilerManger/ProfilerEventCreator.cpp | 60 +++ .../ProfilerManger/ProfilerEventCreator.h | 70 +++ .../ProfilerManger/ProfilerFactory.cpp | 21 + .../ProfilerManger/ProfilerFactory.h | 14 + .../ProfilerManger/ProfilerJsonSerializers.h | 99 ++++ .../ProfilerManger/ProfilerMacro.h | 15 + .../ProfilerManger/ProfilerManger.h | 4 + src/ProjectCore/Json/Detail.h | 55 ++ src/ProjectCore/Json/Json.h | 7 + src/ProjectCore/Json/JsonFactory.h | 84 +++ src/ProjectCore/Json/JsonFormatter.h | 113 ++++ src/ProjectCore/Json/JsonFormatterImpl.h | 39 ++ src/ProjectCore/Json/JsonObjects.cpp | 59 +++ src/ProjectCore/Json/JsonObjects.h | 212 ++++++++ src/ProjectCore/Json/JsonParser.cpp | 76 +++ src/ProjectCore/Json/JsonParser.h | 125 +++++ src/ProjectCore/Json/JsonSerializer.h | 383 ++++++++++++++ .../Json/Serializers/BaseSerializers.h | 464 +++++++++++++++++ .../Json/Serializers/JsonObjectsSerializer.h | 137 +++++ .../STDSerializers/BasicSTDSerializers.h | 30 ++ .../Serializers/STDSerializers/JSON_map.h | 52 ++ .../STDSerializers/JSON_unordered_map.h | 53 ++ .../Serializers/STDSerializers/JSON_vector.h | 30 ++ .../Json/Serializers/Serializers.h | 5 + src/ProjectCore/LoggerManager/Detail/Detail.h | 46 ++ .../LoggerManager/Detail/LoggerMultiSinks.h | 44 ++ .../LoggerManager/Detail/LoggerSink.h | 108 ++++ src/ProjectCore/LoggerManager/LoggerFactory.h | 13 + .../LoggerManager/LoggerImpl/XLogger.h | 169 ++++++ src/ProjectCore/LoggerManager/LoggerManager.h | 11 + .../LoggerManager/Loggers/BasicLogger.h | 80 +++ .../LoggerManager/Loggers/BasicLoggerMacro.h | 28 + .../Loggers/LoggerMultiSinkFast.h | 56 ++ .../Loggers/LoggerMultiSinkSafe.h | 65 +++ .../LoggerManager/Sinks/FileSink.h | 87 ++++ .../Tester/TestSuite/AllTestSuite.h | 2 + src/ProjectCore/Tester/TestSuite/BasicTest.h | 91 ++++ .../Tester/TestSuite/TestSuite.cpp | 163 ++++++ src/ProjectCore/Tester/TestSuite/TestSuite.h | 256 +++++++++ .../Tester/TestsUtilities/CopyMoveCheck.h | 87 ++++ .../Tester/TestsUtilities/TestsMacros.h | 69 +++ src/ProjectCore/Tools/MapMacro.h | 15 + 172 files changed, 14301 insertions(+) create mode 100644 .bazelrc create mode 100644 .bazelversion create mode 100755 .buildbuddy/workspace_status.bat create mode 100755 .buildbuddy/workspace_status.ps1 create mode 100755 .buildbuddy/workspace_status.sh create mode 100644 .buildkite/linux_amd64.yml create mode 100644 .buildkite/pipeline.yml create mode 100644 .buildkite/template.yml create mode 100644 .buildkite/windows_amd64.yml create mode 100644 .github/workflows/ProjectCore.yml create mode 100644 .gitignore create mode 100644 BUILD create mode 100644 LICENSE create mode 100644 MODULE.bazel create mode 100644 Tests/FMT/BaseFMTTests.h create mode 100644 Tests/FMT/ComplexPattern.cpp create mode 100644 Tests/FMT/Globber.cpp create mode 100644 Tests/FMT/Index.cpp create mode 100644 Tests/FMT/Limits.cpp create mode 100644 Tests/FMT/Shift.cpp create mode 100644 Tests/FMT/Specifier.cpp create mode 100644 Tests/FMT/TextProperties.cpp create mode 100644 Tests/Tests.cpp create mode 100644 WORKSPACE create mode 100644 buildbuddy.yaml create mode 100644 premake5.lua create mode 100644 src/ProjectCore/Core/Core.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/BasicContext.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/BasicContextCoreImpl.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/BasicContextParseImpl.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParser.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParserImpl.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h create mode 100644 src/ProjectCore/FMT/Context/BasicContext/Utils/FMTContextTemplate.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/BaseFormat.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatChrono.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatSTDLib.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesColor.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesFront.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesStyle.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatterForwarders.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextCoreImpl.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextParseImpl.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/FormatterContextArgsTuple.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterANSITextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterNOTextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/IFormatterTextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/FormatterType.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/UtilityFunctions.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/Utils/IndexArgs.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/Utils/NamedArgs.h create mode 100644 src/ProjectCore/FMT/Context/FormatterContext/Utils/STDEnumerable.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/BaseParser.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseChrono.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseSTDLib.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesColor.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesFront.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesStyle.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParserForwarders.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BasicParserContext.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BasicParserContextCoreImpl.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/BasicParserContextParseImpl.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/ParserContextArgsTuple.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/IParserTextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserANSITextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserNOTextPropertiesExecutor.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/ParserType.h create mode 100644 src/ProjectCore/FMT/Context/ParserContext/UtilityFunctions.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBuffer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/Integer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/String.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Integer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Internal.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/String.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/BasicBufferOutManager.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FromFormatData.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/Integer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/String.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FMTBufferOut.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FromFormatData.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/Integer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/String.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/FMTFormatBuffer/FMTFormatBuffer.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/Utils/BufferUtils.h create mode 100644 src/ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h create mode 100644 src/ProjectCore/FMT/Detail/Detail.h create mode 100644 src/ProjectCore/FMT/Detail/Exception.h create mode 100644 src/ProjectCore/FMT/Detail/FormatterHandler/FormatterHandler.h create mode 100644 src/ProjectCore/FMT/Detail/Forwarders.h create mode 100644 src/ProjectCore/FMT/Detail/IndentHandlers.h create mode 100644 src/ProjectCore/FMT/Detail/Specifiers.h create mode 100644 src/ProjectCore/FMT/Detail/TextProperties/BaseTextProperties.h create mode 100644 src/ProjectCore/FMT/Detail/TextProperties/TextProperties.h create mode 100644 src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesColor.h create mode 100644 src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesFront.h create mode 100644 src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesStyle.h create mode 100644 src/ProjectCore/FMT/Detail/Types/Types.h create mode 100644 src/ProjectCore/FMT/Detail/Types/TypesInfo.h create mode 100644 src/ProjectCore/FMT/Detail/Types/TypesTraits.h create mode 100644 src/ProjectCore/FMT/Detail/UtilsContextsFunctions.h create mode 100644 src/ProjectCore/FMT/FMT.h create mode 100644 src/ProjectCore/FMT/Format/CompilationData.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_array.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_deque.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_forward_list.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_list.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_map.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_queue.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_set.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_stack.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_tuple.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_map.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_set.h create mode 100644 src/ProjectCore/FMT/Format/STDContainer/FMT_vector.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/AllEvents.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/Detail.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/Event.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/EventData.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/GetPid.cpp create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/Profiler.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.cpp create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.cpp create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerJsonSerializers.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerMacro.h create mode 100644 src/ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h create mode 100644 src/ProjectCore/Json/Detail.h create mode 100644 src/ProjectCore/Json/Json.h create mode 100644 src/ProjectCore/Json/JsonFactory.h create mode 100644 src/ProjectCore/Json/JsonFormatter.h create mode 100644 src/ProjectCore/Json/JsonFormatterImpl.h create mode 100644 src/ProjectCore/Json/JsonObjects.cpp create mode 100644 src/ProjectCore/Json/JsonObjects.h create mode 100644 src/ProjectCore/Json/JsonParser.cpp create mode 100644 src/ProjectCore/Json/JsonParser.h create mode 100644 src/ProjectCore/Json/JsonSerializer.h create mode 100644 src/ProjectCore/Json/Serializers/BaseSerializers.h create mode 100644 src/ProjectCore/Json/Serializers/JsonObjectsSerializer.h create mode 100644 src/ProjectCore/Json/Serializers/STDSerializers/BasicSTDSerializers.h create mode 100644 src/ProjectCore/Json/Serializers/STDSerializers/JSON_map.h create mode 100644 src/ProjectCore/Json/Serializers/STDSerializers/JSON_unordered_map.h create mode 100644 src/ProjectCore/Json/Serializers/STDSerializers/JSON_vector.h create mode 100644 src/ProjectCore/Json/Serializers/Serializers.h create mode 100644 src/ProjectCore/LoggerManager/Detail/Detail.h create mode 100644 src/ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h create mode 100644 src/ProjectCore/LoggerManager/Detail/LoggerSink.h create mode 100644 src/ProjectCore/LoggerManager/LoggerFactory.h create mode 100644 src/ProjectCore/LoggerManager/LoggerImpl/XLogger.h create mode 100644 src/ProjectCore/LoggerManager/LoggerManager.h create mode 100644 src/ProjectCore/LoggerManager/Loggers/BasicLogger.h create mode 100644 src/ProjectCore/LoggerManager/Loggers/BasicLoggerMacro.h create mode 100644 src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkFast.h create mode 100644 src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkSafe.h create mode 100644 src/ProjectCore/LoggerManager/Sinks/FileSink.h create mode 100644 src/ProjectCore/Tester/TestSuite/AllTestSuite.h create mode 100644 src/ProjectCore/Tester/TestSuite/BasicTest.h create mode 100644 src/ProjectCore/Tester/TestSuite/TestSuite.cpp create mode 100644 src/ProjectCore/Tester/TestSuite/TestSuite.h create mode 100644 src/ProjectCore/Tester/TestsUtilities/CopyMoveCheck.h create mode 100644 src/ProjectCore/Tester/TestsUtilities/TestsMacros.h create mode 100644 src/ProjectCore/Tools/MapMacro.h diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..151bb70 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,17 @@ +# Common +common --enable_platform_specific_config +common --experimental_platforms_api +common --show_timestamps +common --verbose_failures +test --test_output=errors + +# Build +common:linux --config=default_compiler_opt +common:msvc --config=microsoft_compiler_opt + +common:default_compiler_opt --copt -std=c++20 +common:microsoft_compiler_opt --copt /std:c++20 + +# BuildBuddy +common:linux --workspace_status_command=$(pwd)/.buildbuddy/workspace_status.sh +common:windows --workspace_status_command=.buildbuddy/workspace_status.bat diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..e69de29 diff --git a/.buildbuddy/workspace_status.bat b/.buildbuddy/workspace_status.bat new file mode 100755 index 0000000..cc31c36 --- /dev/null +++ b/.buildbuddy/workspace_status.bat @@ -0,0 +1,2 @@ +@echo off +call PowerShell -NoProfile -ExecutionPolicy Bypass -Command "%CD%\.buildbuddy\workspace_status.ps1" diff --git a/.buildbuddy/workspace_status.ps1 b/.buildbuddy/workspace_status.ps1 new file mode 100755 index 0000000..a2c1a20 --- /dev/null +++ b/.buildbuddy/workspace_status.ps1 @@ -0,0 +1,33 @@ +# This script will be run by Bazel when the building process starts to +# generate key-value information that represents the status of the +# workspace. The output should be like +# +# KEY1 VALUE1 +# KEY2 VALUE2 +# +# If the script exits with a non-zero code, it's considered as a failure +# and the output will be discarded. + +$ErrorActionPreference = "Stop" + +# Get the repository URL without credentials +$repo_url = (git config --get remote.origin.url) -replace '//.*?:.*?@', '//' +$repo_url = $repo_url -replace '^git@github.com:', 'https://github.com/' +$urrepo_urll = $repo_url -replace '\.git$' +Write-Output "REPO_URL $repo_url" + +# Get the commit SHA +$commit_sha = git rev-parse HEAD +Write-Output "COMMIT_SHA $commit_sha" + +# Get the current Git branch +$git_branch = git rev-parse --abbrev-ref HEAD +Write-Output "GIT_BRANCH $git_branch" + +# Check if there are any modified files in the working directory +if (git diff-index --quiet HEAD) { + $git_tree_status = 'Clean' +} else { + $git_tree_status = 'Modified' +} +Write-Output "GIT_TREE_STATUS $git_tree_status" diff --git a/.buildbuddy/workspace_status.sh b/.buildbuddy/workspace_status.sh new file mode 100755 index 0000000..df1dac9 --- /dev/null +++ b/.buildbuddy/workspace_status.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# This script will be run bazel when building process starts to +# generate key-value information that represents the status of the +# workspace. The output should be like +# +# KEY1 VALUE1 +# KEY2 VALUE2 +# +# If the script exits with non-zero code, it's considered as a failure +# and the output will be discarded. + +set -eo pipefail # exit immediately if any command fails. + +function remove_url_credentials() { + which perl >/dev/null && perl -pe 's#//.*?:.*?@#//#' || cat +} + +repo_url=$(git config --get remote.origin.url | remove_url_credentials) +repo_url=${repo_url/git@github.com:/https://github.com/} +repo_url=${repo_url%.git} +echo "REPO_URL $repo_url" + +commit_sha=$(git rev-parse HEAD) +echo "COMMIT_SHA $commit_sha" + +git_branch=$(git rev-parse --abbrev-ref HEAD) +echo "GIT_BRANCH $git_branch" + +git_tree_status=$(git diff-index --quiet HEAD -- && echo 'Clean' || echo 'Modified') +echo "GIT_TREE_STATUS $git_tree_status" diff --git a/.buildkite/linux_amd64.yml b/.buildkite/linux_amd64.yml new file mode 100644 index 0000000..c9e5a06 --- /dev/null +++ b/.buildkite/linux_amd64.yml @@ -0,0 +1,17 @@ +agents: + queue: "agent-runners-linux-amd64" + +steps: + - label: ":bazel: Build on gcc" + commands: + - CC=gcc bazelisk build //... + - label: ":bazel: Test on gcc" + commands: + - CC=gcc bazelisk test //... + + - label: ":bazel: Build on Clang" + commands: + - CC=clang bazelisk build //... + - label: ":bazel: Test on Clang" + commands: + - CC=clang bazelisk test //... diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000..b9d8345 --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,5 @@ +steps: + - label: ":pipeline: Launch Windows Pipeline" + command: "buildkite-agent pipeline upload .buildkite/windows_amd64.yml" + - label: ":pipeline: Launch Linux Pipeline" + command: "buildkite-agent pipeline upload .buildkite/linux_amd64.yml" diff --git a/.buildkite/template.yml b/.buildkite/template.yml new file mode 100644 index 0000000..56c0e9b --- /dev/null +++ b/.buildkite/template.yml @@ -0,0 +1,4 @@ +name: "ProjectCore" +steps: + - label: ":pipeline: Launch Embbeded Pipeline" + command: "buildkite-agent pipeline upload .builkite/pipeline.yml" diff --git a/.buildkite/windows_amd64.yml b/.buildkite/windows_amd64.yml new file mode 100644 index 0000000..ad18bd5 --- /dev/null +++ b/.buildkite/windows_amd64.yml @@ -0,0 +1,10 @@ +agents: + queue: "agent-runners-windows-amd64" + +steps: + - label: ":bazel: Build" + commands: + - bazelisk build //... + - label: ":bazel: Test" + commands: + - bazelisk test //... diff --git a/.github/workflows/ProjectCore.yml b/.github/workflows/ProjectCore.yml new file mode 100644 index 0000000..cfc2786 --- /dev/null +++ b/.github/workflows/ProjectCore.yml @@ -0,0 +1,64 @@ +name: ProjectCore + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + windows-latest-msvc: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Building... + run: bazelisk build //... + - name: Testing... + run: bazelisk test //... + + ubuntu-latest-gcc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Version + run: gcc --version + - name: Building... + run: CC=gcc bazelisk build //... + - name: Testing... + run: CC=gcc bazelisk test //... + + ubuntu-latest-clang: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Install clang + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x ./llvm.sh + sudo ./llvm.sh 17 + - name: Version + run: clang --version + - name: Building... + run: CC=clang++-17 bazelisk build //... + - name: Testing... + run: CC=clang++-17 bazelisk test //... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e79eab --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ + +# bazel +MODULE.bazel.lock +bazel-bin +bazel-out +bazel-projectcore +bazel-testlogs + +# VS +.vs +*.sln +*.vcxproj +*.vcxproj.filters +*.vcxproj.user + +# Make +Makefile +*.make + +# VSCode +.vscode + +# VSCode +bin +bin-int + +# Asset +Asset + +# Tests +TestSuite_FMT.json diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..c966da1 --- /dev/null +++ b/BUILD @@ -0,0 +1,22 @@ +"" + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + +cc_library( + name = "ProjectCore", + srcs = glob([ "src/**/*.h", "src/**/*.cpp" ]), + hdrs = glob([ "src/**/*.h" ]), + includes = [ "src/" ], + strip_include_prefix = "src", + include_prefix = "ProjectCore", + linkstatic = True, + visibility = ["//visibility:public"], +) + +cc_test( + name = "ProjectCoreTests", + includes = [ "src/" ], + srcs = glob([ "Tests/**/*.h", "Tests/**/*.cpp" ]), + deps = [ ":ProjectCore" ], + visibility = ["//visibility:public"], +) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ff90aae --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Bellier Sacha + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..7297d97 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,10 @@ +"" + +# buildifier: disable=module-docstring +module( + name = "projectcore", + version = "0.1", + repo_name = "com_sacha_projectcore", +) + +bazel_dep(name = "rules_cc", version = "0.0.4") diff --git a/Tests/FMT/BaseFMTTests.h b/Tests/FMT/BaseFMTTests.h new file mode 100644 index 0000000..dad49c2 --- /dev/null +++ b/Tests/FMT/BaseFMTTests.h @@ -0,0 +1,5 @@ +#pragma once + +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" + +inline PCT_TEST_SUITE(FMT); diff --git a/Tests/FMT/ComplexPattern.cpp b/Tests/FMT/ComplexPattern.cpp new file mode 100644 index 0000000..2ebaba1 --- /dev/null +++ b/Tests/FMT/ComplexPattern.cpp @@ -0,0 +1,15 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, COMPLEX_PATTERN); + +#define TEST_FMT(fmt_test, expected, ...) PCT_EQ(ProjectCore::FMT::FormatString(fmt_test, __VA_ARGS__), expected) + +PCT_TEST_FUNC(COMPLEX_PATTERN, UNESCAPED_ESCAPE_PATTERN) +{ + TEST_FMT("{0}", "9", 9); + TEST_FMT("{{0}|", "{9|", 9); + TEST_FMT("{{0},", "{9,", 9); +} diff --git a/Tests/FMT/Globber.cpp b/Tests/FMT/Globber.cpp new file mode 100644 index 0000000..3921dad --- /dev/null +++ b/Tests/FMT/Globber.cpp @@ -0,0 +1,73 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" +#include "ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, GLOBBER); +#define TEST_GLOBBER(data, glob) \ + { \ + ProjectCore::FMT::Detail::BasicBufferIn p_buffer(data); \ + ProjectCore::FMT::Detail::BasicBufferIn p_glob(glob); \ + ProjectCore::FMT::Detail::Globber::BufferInExecGlob(p_buffer, p_glob); \ + PCT_ASSERT(p_buffer.IsEnd()); \ + } + +PCT_TEST_FUNC(GLOBBER, BASIC_WILDCARD) +{ + TEST_GLOBBER("qwerty", "qwerty") + TEST_GLOBBER("qwerty", "q?erty") + TEST_GLOBBER("qwerty", "q?????") + TEST_GLOBBER("qwerty", "qwer?y") + TEST_GLOBBER("qwerty", "qwert?") + TEST_GLOBBER("qwerty", "??????") + TEST_GLOBBER("qwerty", "*") + TEST_GLOBBER("qwerty", "******") + TEST_GLOBBER("qwerty", "*?**?*") +} + +PCT_TEST_GROUP(FMT, PARSE_GLOBBER); +PCT_TEST_FUNC(PARSE_GLOBBER, PG_BASIC_WILDCARD) +{ + int k = 0; + ProjectCore::FMT::Parse("|123|", "|{}|", k); + PCT_EQ(k, 123); + + { + char test[5]; + ProjectCore::FMT::Parse("|test|", "|{}|", test); + PCT_EQ(std::string(test), std::string("test")); + } + + { + char test[4]; + ProjectCore::FMT::Parse("|test|", "|{:no-zero-end}|", test); + PCT_EQ(std::string(test, 4), std::string("test")); + } + + { + char test[4]; + ProjectCore::FMT::Parse("|test|", "|{}t|", test); + PCT_EQ(std::string(test), std::string("tes")); + } + + { + char test[11]; + ProjectCore::FMT::Parse("|test123456|", "|{}|", test); + PCT_EQ(std::string(test), std::string("test123456")); + } + + { + char test[11]; + ProjectCore::FMT::Parse("|test123456|", "|{:glob='*1'}23456|", test); + PCT_EQ(std::string(test), std::string("test1")); + } + + { + char test[11]; + // just glob = '????' but compiler are anrgy about trigraph on '??' + ProjectCore::FMT::Parse("|test123456|", "|{:glob='?""?""?""?'}123456|", test); + PCT_EQ(std::string(test), std::string("test")); + } +} + diff --git a/Tests/FMT/Index.cpp b/Tests/FMT/Index.cpp new file mode 100644 index 0000000..02dd86e --- /dev/null +++ b/Tests/FMT/Index.cpp @@ -0,0 +1,12 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +/* +PCT_TEST_GROUP(FMT, INDEX); + +PCT_TEST_FUNC(INDEX, ReIndexing) +{ +} +*/ diff --git a/Tests/FMT/Limits.cpp b/Tests/FMT/Limits.cpp new file mode 100644 index 0000000..0f2fcd2 --- /dev/null +++ b/Tests/FMT/Limits.cpp @@ -0,0 +1,115 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, LIMITS); + +#define PCT_TEST_FUNC_LowBufferSize(k) \ + PCT_TEST_FUNC(LIMITS, LowBufferSize ## k)\ + {\ + char buffer[k] = { 0 };\ + ProjectCore::FMT::FormatInChar(buffer, "0123456789");\ + for (int i = 0; i < k; ++i)\ + PCT_EQ(buffer[i] - '0', i);\ + } + +PCT_TEST_FUNC_LowBufferSize(10); +PCT_TEST_FUNC_LowBufferSize(9); +PCT_TEST_FUNC_LowBufferSize(8); +PCT_TEST_FUNC_LowBufferSize(7); +PCT_TEST_FUNC_LowBufferSize(6); +PCT_TEST_FUNC_LowBufferSize(5); +PCT_TEST_FUNC_LowBufferSize(4); +PCT_TEST_FUNC_LowBufferSize(3); +PCT_TEST_FUNC_LowBufferSize(2); +PCT_TEST_FUNC_LowBufferSize(1); + +PCT_TEST_FUNC(LIMITS, PlainLowBufferSize10) +{ + char buffer[10] = { 0 }; + ProjectCore::FMT::FormatInChar(buffer, "0123456789"); + for (int i = 0; i < 10; ++i) + PCT_EQ(buffer[i] - '0', i); +} + +PCT_TEST_FUNC(LIMITS, PlainLowBufferSize1) +{ + char buffer[1] = { 0 }; + ProjectCore::FMT::FormatInChar(buffer, "0"); + for (int i = 0; i < 1; ++i) + PCT_EQ(buffer[i] - '0', i); +} + +#define PCT_TEST_FUNC_LowBufferSizeArray(k) \ + PCT_TEST_FUNC(LIMITS, LowBufferSizeArray ## k)\ + {\ + char buffer[k] = { 0 };\ + const char fmtBuffer[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };\ + ProjectCore::FMT::Detail::BufferInProperties properties(fmtBuffer, k);\ + ProjectCore::FMT::Detail::GivenBufferOutManager manager(buffer, k);\ + ProjectCore::FMT::Detail::FormatInBufferOutManager(manager, properties, false);\ + for (int i = 0; i < k; ++i)\ + PCT_EQ(buffer[i] - '0', i);\ + } + +PCT_TEST_FUNC_LowBufferSizeArray(10); +PCT_TEST_FUNC_LowBufferSizeArray(9); +PCT_TEST_FUNC_LowBufferSizeArray(8); +PCT_TEST_FUNC_LowBufferSizeArray(7); +PCT_TEST_FUNC_LowBufferSizeArray(6); +PCT_TEST_FUNC_LowBufferSizeArray(5); +PCT_TEST_FUNC_LowBufferSizeArray(4); +PCT_TEST_FUNC_LowBufferSizeArray(3); +PCT_TEST_FUNC_LowBufferSizeArray(2); +PCT_TEST_FUNC_LowBufferSizeArray(1); + +PCT_TEST_FUNC(LIMITS, PlainLowBufferSizeArray10) +{ + char buffer[10] = { 0 }; + const char fmtBuffer[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + ProjectCore::FMT::Detail::BufferInProperties properties(fmtBuffer, 10); + ProjectCore::FMT::Detail::GivenBufferOutManager manager(buffer, 10); + ProjectCore::FMT::Detail::FormatInBufferOutManager(manager, properties, false); + for (int i = 0; i < 10; ++i) + PCT_EQ(buffer[i] - '0', i); +} + +PCT_TEST_FUNC(LIMITS, PlainLowBufferSizeArray1) +{ + char buffer[1] = { 0 }; + const char fmtBuffer[] = { '0' }; + ProjectCore::FMT::Detail::BufferInProperties properties(fmtBuffer, 1); + ProjectCore::FMT::Detail::GivenBufferOutManager manager(buffer, 1); + ProjectCore::FMT::Detail::FormatInBufferOutManager(manager, properties, false); + for (int i = 0; i < 1; ++i) + PCT_EQ(buffer[i] - '0', i); +} + + + +PCT_TEST_FUNC(LIMITS, LowBufferSizeArray10FMT30) +{ + char buffer[10] = { 0 }; + const char fmtBuffer[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + }; + ProjectCore::FMT::Detail::BufferInProperties properties(fmtBuffer, 30); + ProjectCore::FMT::Detail::GivenBufferOutManager manager(buffer, 10); + ProjectCore::FMT::Detail::FormatInBufferOutManager(manager, properties, false); + for (int k = 0; k < 10; ++k) + PCT_EQ(buffer[k] - '0', k); +} + + +PCT_TEST_FUNC(LIMITS, LowBufferSizeArray5Number9) +{ + char buffer[10] = { 0 }; + ProjectCore::FMT::Detail::BufferInProperties properties("{}"); + ProjectCore::FMT::Detail::GivenBufferOutManager manager(buffer, 10); + std::uint64_t i = 9'876'543'210; + ProjectCore::FMT::Detail::FormatInBufferOutManager(manager, properties, false, i); + for (int k = 0; k < 10; ++k) + PCT_EQ(buffer[k] - '0', 9 - k); +} diff --git a/Tests/FMT/Shift.cpp b/Tests/FMT/Shift.cpp new file mode 100644 index 0000000..f18ae28 --- /dev/null +++ b/Tests/FMT/Shift.cpp @@ -0,0 +1,329 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, SHIFT); + +#define TEST_FMT(fmt_test, expected, ...) PCT_EQ(ProjectCore::FMT::FormatString(fmt_test, __VA_ARGS__), expected) + +PCT_TEST_GROUP(SHIFT, NUMBER_SHIFT); +PCT_TEST_GROUP(NUMBER_SHIFT, ONE_DIGIT); +PCT_TEST_FUNC(ONE_DIGIT, Right) +{ + TEST_FMT("|{:>9 }|", "| 7|", 7); + TEST_FMT("|{:>9: }|", "| 7|", 7); + TEST_FMT("|{:>9:0}|", "|000000007|", 7); + TEST_FMT("|{:>9:*}|", "|********7|", 7); + +} +PCT_TEST_FUNC(ONE_DIGIT, Left) +{ + TEST_FMT("|{:<9 }|", "|7 |", 7); + TEST_FMT("|{:<9: }|", "|7 |", 7); + TEST_FMT("|{:<9:0}|", "|7 |", 7); + TEST_FMT("|{:<9:*}|", "|7********|", 7); +} +PCT_TEST_FUNC(ONE_DIGIT, Center) +{ + TEST_FMT("|{:^10 }|", "| 7 |", 7); + TEST_FMT("|{:^10:-|-}|", "|-----7----|", 7); + TEST_FMT("|{:^10:*|*}|", "|*****7****|", 7); + TEST_FMT("|{:^10:<|>}|", "|<<<<<7>>>>|", 7); + TEST_FMT("|{:^10:>|<}|", "|>>>>>7<<<<|", 7); + + TEST_FMT("|{:^11:-|-}|", "|-----7-----|", 7); + TEST_FMT("|{:^11:*|*}|", "|*****7*****|", 7); + TEST_FMT("|{:^11:<|>}|", "|<<<<<7>>>>>|", 7); + TEST_FMT("|{:^11:>|<}|", "|>>>>>7<<<<<|", 7); +} +PCT_TEST_FUNC(ONE_DIGIT, CenterRight) +{ + TEST_FMT("|{:^>10:-|-}|", "|-----7----|", 7); + TEST_FMT("|{:^>10:*|*}|", "|*****7****|", 7); + TEST_FMT("|{:^>10:<|>}|", "|<<<<<7>>>>|", 7); + TEST_FMT("|{:^>10:>|<}|", "|>>>>>7<<<<|", 7); + + TEST_FMT("|{:^>11:-|-}|", "|-----7-----|", 7); + TEST_FMT("|{:^>11:*|*}|", "|*****7*****|", 7); + TEST_FMT("|{:^>11:<|>}|", "|<<<<<7>>>>>|", 7); + TEST_FMT("|{:^>11:>|<}|", "|>>>>>7<<<<<|", 7); +} +PCT_TEST_FUNC(ONE_DIGIT, CenterLeft) +{ + TEST_FMT("|{:^<10:-|-}|", "|----7-----|", 7); + TEST_FMT("|{:^<10:*|*}|", "|****7*****|", 7); + TEST_FMT("|{:^<10:<|>}|", "|<<<<7>>>>>|", 7); + TEST_FMT("|{:^<10:>|<}|", "|>>>>7<<<<<|", 7); + + TEST_FMT("|{:^<11:-|-}|", "|-----7-----|", 7); + TEST_FMT("|{:^<11:*|*}|", "|*****7*****|", 7); + TEST_FMT("|{:^<11:<|>}|", "|<<<<<7>>>>>|", 7); + TEST_FMT("|{:^<11:>|<}|", "|>>>>>7<<<<<|", 7); +} + + +PCT_TEST_GROUP(NUMBER_SHIFT, TWO_DIGIT); +PCT_TEST_FUNC(TWO_DIGIT, Right) +{ + TEST_FMT("|{:>10 }|", "| 14|", 14); + TEST_FMT("|{:>10: }|", "| 14|", 14); + TEST_FMT("|{:>10:0}|", "|0000000014|", 14); + TEST_FMT("|{:>10:*}|", "|********14|", 14); +} +PCT_TEST_FUNC(TWO_DIGIT, Left) +{ + TEST_FMT("|{:<10 }|", "|14 |", 14); + TEST_FMT("|{:<10: }|", "|14 |", 14); + TEST_FMT("|{:<10:0}|", "|14 |", 14); + TEST_FMT("|{:<10:*}|", "|14********|", 14); +} +PCT_TEST_FUNC(TWO_DIGIT, Center) +{ + TEST_FMT("|{:^10 }|", "| 14 |", 14); + TEST_FMT("|{:^10:-|-}|", "|----14----|", 14); + TEST_FMT("|{:^10:*|*}|", "|****14****|", 14); + TEST_FMT("|{:^10:<|>}|", "|<<<<14>>>>|", 14); + TEST_FMT("|{:^10:>|<}|", "|>>>>14<<<<|", 14); + + TEST_FMT("|{:^11:-|-}|", "|-----14----|", 14); + TEST_FMT("|{:^11:*|*}|", "|*****14****|", 14); + TEST_FMT("|{:^11:<|>}|", "|<<<<<14>>>>|", 14); + TEST_FMT("|{:^11:>|<}|", "|>>>>>14<<<<|", 14); +} +PCT_TEST_FUNC(TWO_DIGIT, CenterRight) +{ + TEST_FMT("|{:^>10:-|-}|", "|----14----|", 14); + TEST_FMT("|{:^>10:*|*}|", "|****14****|", 14); + TEST_FMT("|{:^>10:<|>}|", "|<<<<14>>>>|", 14); + TEST_FMT("|{:^>10:>|<}|", "|>>>>14<<<<|", 14); + + TEST_FMT("|{:^>11:-|-}|", "|-----14----|", 14); + TEST_FMT("|{:^>11:*|*}|", "|*****14****|", 14); + TEST_FMT("|{:^>11:<|>}|", "|<<<<<14>>>>|", 14); + TEST_FMT("|{:^>11:>|<}|", "|>>>>>14<<<<|", 14); +} +PCT_TEST_FUNC(TWO_DIGIT, CenterLeft) +{ + TEST_FMT("|{:^<10:-|-}|", "|----14----|", 14); + TEST_FMT("|{:^<10:*|*}|", "|****14****|", 14); + TEST_FMT("|{:^<10:<|>}|", "|<<<<14>>>>|", 14); + TEST_FMT("|{:^<10:>|<}|", "|>>>>14<<<<|", 14); + + TEST_FMT("|{:^<11:-|-}|", "|----14-----|", 14); + TEST_FMT("|{:^<11:*|*}|", "|****14*****|", 14); + TEST_FMT("|{:^<11:<|>}|", "|<<<<14>>>>>|", 14); + TEST_FMT("|{:^<11:>|<}|", "|>>>>14<<<<<|", 14); +} + + +PCT_TEST_GROUP(NUMBER_SHIFT, THREE_DIGIT); +PCT_TEST_FUNC(THREE_DIGIT, Right) +{ + TEST_FMT("|{:>11 }|", "| 105|", 105); + TEST_FMT("|{:>11: }|", "| 105|", 105); + TEST_FMT("|{:>11:0}|", "|00000000105|", 105); + TEST_FMT("|{:>11:*}|", "|********105|", 105); +} +PCT_TEST_FUNC(THREE_DIGIT, Left) +{ + TEST_FMT("|{:<11 }|", "|105 |", 105); + TEST_FMT("|{:<11: }|", "|105 |", 105); + TEST_FMT("|{:<11:0}|", "|105 |", 105); + TEST_FMT("|{:<11:*}|", "|105********|", 105); +} +PCT_TEST_FUNC(THREE_DIGIT, Center) +{ + TEST_FMT("|{:^10 }|", "| 105 |", 105); + TEST_FMT("|{:^10:-|-}|", "|----105---|", 105); + TEST_FMT("|{:^10:*|*}|", "|****105***|", 105); + TEST_FMT("|{:^10:<|>}|", "|<<<<105>>>|", 105); + TEST_FMT("|{:^10:>|<}|", "|>>>>105<<<|", 105); + + TEST_FMT("|{:^11:-|-}|", "|----105----|", 105); + TEST_FMT("|{:^11:*|*}|", "|****105****|", 105); + TEST_FMT("|{:^11:<|>}|", "|<<<<105>>>>|", 105); + TEST_FMT("|{:^11:>|<}|", "|>>>>105<<<<|", 105); +} +PCT_TEST_FUNC(THREE_DIGIT, CenterRight) +{ + TEST_FMT("|{:^>10:-|-}|", "|----105---|", 105); + TEST_FMT("|{:^>10:*|*}|", "|****105***|", 105); + TEST_FMT("|{:^>10:<|>}|", "|<<<<105>>>|", 105); + TEST_FMT("|{:^>10:>|<}|", "|>>>>105<<<|", 105); + + TEST_FMT("|{:^>11:-|-}|", "|----105----|", 105); + TEST_FMT("|{:^>11:*|*}|", "|****105****|", 105); + TEST_FMT("|{:^>11:<|>}|", "|<<<<105>>>>|", 105); + TEST_FMT("|{:^>11:>|<}|", "|>>>>105<<<<|", 105); +} +PCT_TEST_FUNC(THREE_DIGIT, CenterLeft) +{ + TEST_FMT("|{:^<10:-|-}|", "|---105----|", 105); + TEST_FMT("|{:^<10:*|*}|", "|***105****|", 105); + TEST_FMT("|{:^<10:<|>}|", "|<<<105>>>>|", 105); + TEST_FMT("|{:^<10:>|<}|", "|>>>105<<<<|", 105); + + TEST_FMT("|{:^<11:-|-}|", "|----105----|", 105); + TEST_FMT("|{:^<11:*|*}|", "|****105****|", 105); + TEST_FMT("|{:^<11:<|>}|", "|<<<<105>>>>|", 105); + TEST_FMT("|{:^<11:>|<}|", "|>>>>105<<<<|", 105); +} + +PCT_TEST_GROUP(SHIFT, STRING_SHIFT); +PCT_TEST_GROUP(STRING_SHIFT, ARRAY); +PCT_TEST_FUNC(ARRAY, Right) +{ + TEST_FMT("|{:>10 }|", "| test|", "test"); + TEST_FMT("|{:>10: }|", "| test|", "test"); + TEST_FMT("|{:>10:0}|", "|000000test|", "test"); + TEST_FMT("|{:>10:*}|", "|******test|", "test"); +} +PCT_TEST_FUNC(ARRAY, Left) +{ + TEST_FMT("|{:<10 }|", "|test |", "test"); + TEST_FMT("|{:<10: }|", "|test |", "test"); + TEST_FMT("|{:<10:0}|", "|test000000|", "test"); + TEST_FMT("|{:<10:*}|", "|test******|", "test"); +} +PCT_TEST_FUNC(ARRAY, Center) +{ + TEST_FMT("|{:^10 }|", "| test |", "test"); + TEST_FMT("|{:^10:-|-}|", "|---test---|", "test"); + TEST_FMT("|{:^10:*|*}|", "|***test***|", "test"); + TEST_FMT("|{:^10:<|>}|", "|<<>>|", "test"); + TEST_FMT("|{:^10:>|<}|", "|>>>test<<<|", "test"); + + TEST_FMT("|{:^11:-|-}|", "|----test---|", "test"); + TEST_FMT("|{:^11:*|*}|", "|****test***|", "test"); + TEST_FMT("|{:^11:<|>}|", "|<<<>>|", "test"); + TEST_FMT("|{:^11:>|<}|", "|>>>>test<<<|", "test"); +} +PCT_TEST_FUNC(ARRAY, CenterRight) +{ + TEST_FMT("|{:^>10:-|-}|", "|---test---|", "test"); + TEST_FMT("|{:^>10:*|*}|", "|***test***|", "test"); + TEST_FMT("|{:^>10:<|>}|", "|<<>>|", "test"); + TEST_FMT("|{:^>10:>|<}|", "|>>>test<<<|", "test"); + + TEST_FMT("|{:^>11:-|-}|", "|----test---|", "test"); + TEST_FMT("|{:^>11:*|*}|", "|****test***|", "test"); + TEST_FMT("|{:^>11:<|>}|", "|<<<>>|", "test"); + TEST_FMT("|{:^>11:>|<}|", "|>>>>test<<<|", "test"); +} +PCT_TEST_FUNC(ARRAY, CenterLeft) +{ + TEST_FMT("|{:^<10:-|-}|", "|---test---|", "test"); + TEST_FMT("|{:^<10:*|*}|", "|***test***|", "test"); + TEST_FMT("|{:^<10:<|>}|", "|<<>>|", "test"); + TEST_FMT("|{:^<10:>|<}|", "|>>>test<<<|", "test"); + + TEST_FMT("|{:^<11:-|-}|", "|---test----|", "test"); + TEST_FMT("|{:^<11:*|*}|", "|***test****|", "test"); + TEST_FMT("|{:^<11:<|>}|", "|<<>>>|", "test"); + TEST_FMT("|{:^<11:>|<}|", "|>>>test<<<<|", "test"); +} + +PCT_TEST_GROUP(STRING_SHIFT, POINTER); +PCT_TEST_FUNC(POINTER, Right) +{ + const char *test = "test"; + TEST_FMT("|{:>10 }|", "| test|", test); + TEST_FMT("|{:>10: }|", "| test|", test); + TEST_FMT("|{:>10:0}|", "|000000test|", test); + TEST_FMT("|{:>10:*}|", "|******test|", test); + + const char *test_with_size = "test_with_size"; + TEST_FMT("|{:>10 , size=4}|", "| test|", test_with_size); + TEST_FMT("|{:>10: , size=4}|", "| test|", test_with_size); + TEST_FMT("|{:>10:0, size=4}|", "|000000test|", test_with_size); + TEST_FMT("|{:>10:*, size=4}|", "|******test|", test_with_size); +} +PCT_TEST_FUNC(POINTER, Left) +{ + const char *test = "test"; + TEST_FMT("|{:<10 }|", "|test |", test); + TEST_FMT("|{:<10: }|", "|test |", test); + TEST_FMT("|{:<10:0}|", "|test000000|", test); + TEST_FMT("|{:<10:*}|", "|test******|", test); + + const char *test_with_size = "test_with_size"; + TEST_FMT("|{:<10 , size=4}|", "|test |", test_with_size); + TEST_FMT("|{:<10: , size=4}|", "|test |", test_with_size); + TEST_FMT("|{:<10:0, size=4}|", "|test000000|", test_with_size); + TEST_FMT("|{:<10:*, size=4}|", "|test******|", test_with_size); +} +PCT_TEST_FUNC(POINTER, Center) +{ + const char *test = "test"; + TEST_FMT("|{:^10 }|", "| test |", test); + TEST_FMT("|{:^10:-|-}|", "|---test---|", test); + TEST_FMT("|{:^10:*|*}|", "|***test***|", test); + TEST_FMT("|{:^10:<|>}|", "|<<>>|", test); + TEST_FMT("|{:^10:>|<}|", "|>>>test<<<|", test); + + TEST_FMT("|{:^11:-|-}|", "|----test---|", test); + TEST_FMT("|{:^11:*|*}|", "|****test***|", test); + TEST_FMT("|{:^11:<|>}|", "|<<<>>|", test); + TEST_FMT("|{:^11:>|<}|", "|>>>>test<<<|", test); + + const char *test_with_size = "test_with_size"; + TEST_FMT("|{:^10 , size=4}|", "| test |", test_with_size); + TEST_FMT("|{:^10:-|-, size=4}|", "|---test---|", test_with_size); + TEST_FMT("|{:^10:*|*, size=4}|", "|***test***|", test_with_size); + TEST_FMT("|{:^10:<|>, size=4}|", "|<<>>|", test_with_size); + TEST_FMT("|{:^10:>|<, size=4}|", "|>>>test<<<|", test_with_size); + + TEST_FMT("|{:^11:-|-, size=4}|", "|----test---|", test_with_size); + TEST_FMT("|{:^11:*|*, size=4}|", "|****test***|", test_with_size); + TEST_FMT("|{:^11:<|>, size=4}|", "|<<<>>|", test_with_size); + TEST_FMT("|{:^11:>|<, size=4}|", "|>>>>test<<<|", test_with_size); +} +PCT_TEST_FUNC(POINTER, CenterRight) +{ + const char *test = "test"; + TEST_FMT("|{:^>10:-|-}|", "|---test---|", test); + TEST_FMT("|{:^>10:*|*}|", "|***test***|", test); + TEST_FMT("|{:^>10:<|>}|", "|<<>>|", test); + TEST_FMT("|{:^>10:>|<}|", "|>>>test<<<|", test); + + TEST_FMT("|{:^>11:-|-}|", "|----test---|", test); + TEST_FMT("|{:^>11:*|*}|", "|****test***|", test); + TEST_FMT("|{:^>11:<|>}|", "|<<<>>|", test); + TEST_FMT("|{:^>11:>|<}|", "|>>>>test<<<|", test); + + const char *test_with_size = "test_with_size"; + TEST_FMT("|{:^>10:-|-, size=4}|", "|---test---|", test_with_size); + TEST_FMT("|{:^>10:*|*, size=4}|", "|***test***|", test_with_size); + TEST_FMT("|{:^>10:<|>, size=4}|", "|<<>>|", test_with_size); + TEST_FMT("|{:^>10:>|<, size=4}|", "|>>>test<<<|", test_with_size); + + TEST_FMT("|{:^>11:-|-, size=4}|", "|----test---|", test_with_size); + TEST_FMT("|{:^>11:*|*, size=4}|", "|****test***|", test_with_size); + TEST_FMT("|{:^>11:<|>, size=4}|", "|<<<>>|", test_with_size); + TEST_FMT("|{:^>11:>|<, size=4}|", "|>>>>test<<<|", test_with_size); +} +PCT_TEST_FUNC(POINTER, CenterLeft) +{ + const char *test = "test"; + TEST_FMT("|{:^<10:-|-}|", "|---test---|", test); + TEST_FMT("|{:^<10:*|*}|", "|***test***|", test); + TEST_FMT("|{:^<10:<|>}|", "|<<>>|", test); + TEST_FMT("|{:^<10:>|<}|", "|>>>test<<<|", test); + + TEST_FMT("|{:^<11:-|-}|", "|---test----|", test); + TEST_FMT("|{:^<11:*|*}|", "|***test****|", test); + TEST_FMT("|{:^<11:<|>}|", "|<<>>>|", test); + TEST_FMT("|{:^<11:>|<}|", "|>>>test<<<<|", test); + + const char *test_with_size = "test_with_size"; + TEST_FMT("|{:^<10:-|-, size=4}|", "|---test---|", test_with_size); + TEST_FMT("|{:^<10:*|*, size=4}|", "|***test***|", test_with_size); + TEST_FMT("|{:^<10:<|>, size=4}|", "|<<>>|", test_with_size); + TEST_FMT("|{:^<10:>|<, size=4}|", "|>>>test<<<|", test_with_size); + + TEST_FMT("|{:^<11:-|-, size=4}|", "|---test----|", test_with_size); + TEST_FMT("|{:^<11:*|*, size=4}|", "|***test****|", test_with_size); + TEST_FMT("|{:^<11:<|>, size=4}|", "|<<>>>|", test_with_size); + TEST_FMT("|{:^<11:>|<, size=4}|", "|>>>test<<<<|", test_with_size); +} diff --git a/Tests/FMT/Specifier.cpp b/Tests/FMT/Specifier.cpp new file mode 100644 index 0000000..6072fb5 --- /dev/null +++ b/Tests/FMT/Specifier.cpp @@ -0,0 +1,28 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, SPECIFIER); + +#define TEST_FMT_ARRAY_SPECIFIERS(fmt_test, test_data, expected) PCT_EQ(ProjectCore::FMT::FormatString(fmt_test, test_data), expected) + +PCT_TEST_FUNC(SPECIFIER, BEGIN_END) +{ + int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + TEST_FMT_ARRAY_SPECIFIERS("{}", data, "{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }"); + + TEST_FMT_ARRAY_SPECIFIERS("{:begin=6}", data, "{ 6, 7, 8, 9 }"); + TEST_FMT_ARRAY_SPECIFIERS("{:size=5}", data, "{ 0, 1, 2, 3, 4 }"); + TEST_FMT_ARRAY_SPECIFIERS("{:begin=3, size=5}", data, "{ 3, 4, 5, 6, 7 }"); + + TEST_FMT_ARRAY_SPECIFIERS("{:begin='{', begin=3, size=5}", data, "{3, 4, 5, 6, 7 }"); + TEST_FMT_ARRAY_SPECIFIERS("{:end='}', begin=3, size=5}", data, "{ 3, 4, 5, 6, 7}"); + TEST_FMT_ARRAY_SPECIFIERS("{:begin='{', end='}', begin=3, size=5}", data, "{3, 4, 5, 6, 7}"); + TEST_FMT_ARRAY_SPECIFIERS("{:begin='[', end='}', begin=3, size=5}", data, "[3, 4, 5, 6, 7}"); + TEST_FMT_ARRAY_SPECIFIERS("{:begin='[', end=']', begin=3, size=5}", data, "[3, 4, 5, 6, 7]"); + + TEST_FMT_ARRAY_SPECIFIERS("{:join=' ', begin='[', end=']', begin=3, size=5}", data, "[3 4 5 6 7]"); + + TEST_FMT_ARRAY_SPECIFIERS("{:join=' | ', begin='[', end=']', begin=3, size=5}", data, "[3 | 4 | 5 | 6 | 7]"); +} diff --git a/Tests/FMT/TextProperties.cpp b/Tests/FMT/TextProperties.cpp new file mode 100644 index 0000000..5c33633 --- /dev/null +++ b/Tests/FMT/TextProperties.cpp @@ -0,0 +1,97 @@ +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" +#include "ProjectCore/FMT/FMT.h" + +#include "BaseFMTTests.h" + +PCT_TEST_GROUP(FMT, TEXT_PROPERTIES); + +#define TEST_FMT(fmt_test, expected) PCT_EQ(Escaper(ProjectCore::FMT::FormatString(fmt_test, 0)), Escaper(expected)) + +static std::string Escaper(const std::string& str) +{ + std::string res; + for (char c : str) + { + if (c != '\033') + { + res.push_back(c); + continue; + } + + res.push_back('\\'); + res.push_back('e'); + } + return res; +} + +PCT_TEST_GROUP(TEXT_PROPERTIES, ESCAPER_VALIDATING); +#define TEST_ESCAPER(str, str_res) PCT_EQ(Escaper(str), str_res) +PCT_TEST_FUNC(ESCAPER_VALIDATING, BasicTest) +{ + TEST_ESCAPER("\033", "\\e"); + TEST_ESCAPER("\033k", "\\ek"); +} + +PCT_TEST_FUNC(TEXT_PROPERTIES, BasicColor) +{ + TEST_FMT("123", "123"); + + TEST_FMT("{C:black} 123 " , "\033[30m 123 \033[39m"); + TEST_FMT("{C:red} 123 " , "\033[31m 123 \033[39m"); + TEST_FMT("{C:green} 123 " , "\033[32m 123 \033[39m"); + TEST_FMT("{C:yellow} 123 " , "\033[33m 123 \033[39m"); + TEST_FMT("{C:blue} 123 " , "\033[34m 123 \033[39m"); + TEST_FMT("{C:magenta} 123 " , "\033[35m 123 \033[39m"); + TEST_FMT("{C:cyan} 123 " , "\033[36m 123 \033[39m"); + TEST_FMT("{C:white} 123 " , "\033[37m 123 \033[39m"); + + TEST_FMT("{C:+black} 123 " , "\033[90m 123 \033[39m"); + TEST_FMT("{C:+red} 123 " , "\033[91m 123 \033[39m"); + TEST_FMT("{C:+green} 123 " , "\033[92m 123 \033[39m"); + TEST_FMT("{C:+yellow} 123 " , "\033[93m 123 \033[39m"); + TEST_FMT("{C:+blue} 123 " , "\033[94m 123 \033[39m"); + TEST_FMT("{C:+magenta} 123 " , "\033[95m 123 \033[39m"); + TEST_FMT("{C:+cyan} 123 " , "\033[96m 123 \033[39m"); + TEST_FMT("{C:+white} 123 " , "\033[97m 123 \033[39m"); +} + +PCT_TEST_FUNC(TEXT_PROPERTIES, DoubleBasicColor) +{ + TEST_FMT("123", "123"); + + TEST_FMT("{C:black} 1 {C:white} 23 " , "\033[30m 1 \033[37m 23 \033[39m"); + TEST_FMT("{C:red} 1 {C:black} 23 " , "\033[31m 1 \033[30m 23 \033[39m"); + TEST_FMT("{C:green} 1 {C:red} 23 " , "\033[32m 1 \033[31m 23 \033[39m"); + TEST_FMT("{C:yellow} 1 {C:green} 23 " , "\033[33m 1 \033[32m 23 \033[39m"); + TEST_FMT("{C:blue} 1 {C:yellow} 23 " , "\033[34m 1 \033[33m 23 \033[39m"); + TEST_FMT("{C:magenta} 1 {C:blue} 23 " , "\033[35m 1 \033[34m 23 \033[39m"); + TEST_FMT("{C:cyan} 1 {C:magenta} 23 " , "\033[36m 1 \033[35m 23 \033[39m"); + TEST_FMT("{C:white} 1 {C:cyan} 23 " , "\033[37m 1 \033[36m 23 \033[39m"); + + TEST_FMT("{C:+black} 1 {C:+white} 23 " , "\033[90m 1 \033[97m 23 \033[39m"); + TEST_FMT("{C:+red} 1 {C:+black} 23 " , "\033[91m 1 \033[90m 23 \033[39m"); + TEST_FMT("{C:+green} 1 {C:+red} 23 " , "\033[92m 1 \033[91m 23 \033[39m"); + TEST_FMT("{C:+yellow} 1 {C:+green} 23 " , "\033[93m 1 \033[92m 23 \033[39m"); + TEST_FMT("{C:+blue} 1 {C:+yellow} 23 " , "\033[94m 1 \033[93m 23 \033[39m"); + TEST_FMT("{C:+magenta} 1 {C:+blue} 23 " , "\033[95m 1 \033[94m 23 \033[39m"); + TEST_FMT("{C:+cyan} 1 {C:+magenta} 23 " , "\033[96m 1 \033[95m 23 \033[39m"); + TEST_FMT("{C:+white} 1 {C:+cyan} 23 " , "\033[97m 1 \033[96m 23 \033[39m"); +} + + +class TEST_FMT_ContextOut {}; +PROJECTCORE_AUTO_FORMATTER_T(TEST_FMT_ContextOut, "{C:red} TEST_FMT_ContextOut {} ", 0); + +#define TEST_FMT_CONTEXT(fmt_test, expected) PCT_EQ(Escaper(ProjectCore::FMT::FormatString(fmt_test, TEST_FMT_ContextOut{})), Escaper(expected)) + +PCT_TEST_FUNC(TEXT_PROPERTIES, ContextOut) +{ + TEST_FMT_CONTEXT("{}", "\033[31m TEST_FMT_ContextOut 0 \033[39m"); + + TEST_FMT_CONTEXT("{} 123 ", "\033[31m TEST_FMT_ContextOut 0 \033[39m 123 "); + + // TODO : check before doing a TextPropertiesExecution, should only have one \033[31m + TEST_FMT_CONTEXT("{C:red}{} 123 ", "\033[31m TEST_FMT_ContextOut 0 123 \033[39m"); + + TEST_FMT_CONTEXT("{C:+red}{} 123 ", "\033[91m\033[31m TEST_FMT_ContextOut 0 \033[91m 123 \033[39m"); +} diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp new file mode 100644 index 0000000..090a463 --- /dev/null +++ b/Tests/Tests.cpp @@ -0,0 +1,8 @@ + +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" + +int main() +{ + ProjectCore::Tester::TestSuitesManager::Verbose = false; + return ProjectCore::Tester::TestSuitesManager::ExecAllTestSuites(); +} diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..e16c76d --- /dev/null +++ b/WORKSPACE @@ -0,0 +1 @@ +"" diff --git a/buildbuddy.yaml b/buildbuddy.yaml new file mode 100644 index 0000000..5aa70a7 --- /dev/null +++ b/buildbuddy.yaml @@ -0,0 +1,18 @@ +plugins: + - repo: buildbuddy-io/plugins + path: open-invocation + - repo: siggisim/theme-modern + - repo: buildbuddy-io/plugins + path: notify + +actions: + - name: "BuildBuddy Workflows" + triggers: + push: + branches: + - "*" + pull_request: + branches: + - "*" + bazel_commands: + - "test --remote_header=x-buildbuddy-api-key=$BUILDBUDDY_RBEKEY_WINDOWS_WSL //..." diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 0000000..3a0c3ae --- /dev/null +++ b/premake5.lua @@ -0,0 +1,62 @@ + +-- TODO:bazel remove Solution.Projects Infos: +Solution.Projects["ProjectCore"].PlatformDefineName = "PROJECTCORE" +Solution.Projects["ProjectCore"].Type = "StaticLib" +Solution.Projects["ProjectCore"].IncludeDirs = { + "%{Solution.Projects.ProjectCore.Path}/src/" +} + +project "ProjectCore" + kind (Solution.Projects["ProjectCore"].Type) + language "C++" + cppdialect "C++20" + + Solution.HighWarnings() + + targetdir (Solution.Path.ProjectTargetDirectory) + objdir (Solution.Path.ProjectObjectDirectory) + + files { + "src/**.h", + "src/**.inl", + "src/**.cpp", + } + + Solution.Project("ProjectCore") + + defines { + "PROJECTCORE_BASE_LOGGER_NAME=\"%{Solution.Name}\"" + } + +if (ProjectCoreTestsEnable) +then + +Solution.AddProject("ProjectCoreTests", Solution.Projects["ProjectCore"].Path) +Solution.Projects["ProjectCoreTests"].ProjectDependencies = { + "ProjectCore" +} + +ProjectCoreTestsLaunch = {} +ProjectCoreTestsLaunch.Project = "ProjectCoreTests" +Solution.Launch["ProjectCoreTests"] = ProjectCoreTestsLaunch + +project "ProjectCoreTests" + kind (Solution.Projects["ProjectCoreTests"].Type) + language "C++" + cppdialect "C++20" + + Solution.HighWarnings() + + targetdir (Solution.Path.ProjectTargetDirectory) + objdir (Solution.Path.ProjectObjectDirectory) + + files { + "Tests/**.h", + "Tests/**.hpp", + "Tests/**.inl", + "Tests/**.cpp", + } + + Solution.Project("ProjectCoreTests") +end + \ No newline at end of file diff --git a/src/ProjectCore/Core/Core.h b/src/ProjectCore/Core/Core.h new file mode 100644 index 0000000..f4f544e --- /dev/null +++ b/src/ProjectCore/Core/Core.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#ifdef PROJECTCORE_DEBUG +#define PROJECTCORE_ASSERT_ENABLE +#define PROJECTCORE_ONLY_ON_DEBUG(x) x +#else /* PROJECTCORE_DEBUG */ +#define PROJECTCORE_ONLY_ON_DEBUG(x) +#endif /* PROJECTCORE_DEBUG */ + +#ifdef PROJECTCORE_ASSERT_ENABLE + #ifdef UTILITIES_COMPILER_VS + #define PROJECTCORE_DEBUGBREAK() __debugbreak() + #else + #include + #define PROJECTCORE_DEBUGBREAK() std::raise(SIGINT) + #endif + + #define PROJECTCORE_ASSERT(x) if(!(x)) { std::cerr << "ASSERT FAILED! : {}" << #x << std::endl; PROJECTCORE_DEBUGBREAK(); } +#else + #define PROJECTCORE_ASSERT(x) + #define PROJECTCORE_DEBUGBREAK() +#endif + +// NOT USED YET +#define PROJECTCORE_NODISCARD [[nodiscard]] +#define PROJECTCORE_INLINE inline + +#define UNKOWN_TYPE_MESSAGE +#define UNKOWN_TYPE_DEBUG diff --git a/src/ProjectCore/FMT/Context/BasicContext/BasicContext.h b/src/ProjectCore/FMT/Context/BasicContext/BasicContext.h new file mode 100644 index 0000000..9b8c4d7 --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/BasicContext.h @@ -0,0 +1,125 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/FMT/Detail/Buffer/FMTFormatBuffer/FMTFormatBuffer.h" + +#include "ProjectCore/FMT/Detail/FormatterHandler/FormatterHandler.h" +#include "Utils/BasicContextArgsTupleInterface.h" +#include "Utils/FMTContextTemplate.h" + +#include "TextPropertiesParser.h" + +namespace ProjectCore::FMT::Context +{ + template + class BasicContext + { + private: + using M_Type = BasicContext; + + public: + using CharFormatType = CharFormat; + + using FormatDataType = Detail::FormatData; + using FormatSpecifierType = Detail::FormatSpecifier; + + using FormatBufferType = Detail::FMTFormatBuffer; + + using StringViewFormat = std::basic_string_view; + + using ContextArgsInterface = Detail::BasicArgsTupleInterface; + + using TextPropertiesParser = Detail::BasicTextPropertiesParser; + + public: + BasicContext(Detail::ITextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties = nullptr); + virtual ~BasicContext() = default; + void Terminate(); + + protected: + FormatBufferType m_Format; + Detail::FormatIndex m_ValuesIndex; + FormatDataType m_FormatData; + ContextArgsInterface* m_ContextArgsInterface; + TextPropertiesParser m_TextPropertiesParser; + + public: + inline FormatBufferType& Format() { return m_Format; } + inline const FormatBufferType& Format() const { return m_Format; } + + inline FormatDataType& GetFormatData() { return m_FormatData; } + inline const FormatDataType& GetFormatData() const { return m_FormatData; } + inline FormatDataType ForwardFormatData() const { return m_FormatData; } + inline void SetFormatData(const FormatDataType& formatData) { m_FormatData = formatData; } + + inline ContextArgsInterface& GetContextArgsInterface() { return *m_ContextArgsInterface; } + inline const ContextArgsInterface& GetContextArgsInterface() const { return *m_ContextArgsInterface; } + + inline TextPropertiesParser& GetTextPropertiesParser() { return m_TextPropertiesParser; } + inline const TextPropertiesParser& GetTextPropertiesParser() const { return m_TextPropertiesParser; } + + protected: + virtual void SetArgsInterfaceCurrentContex() = 0; + virtual void FormatToParamsString(const CharFormat* buffer, std::size_t size) = 0; + virtual void FormatExecParams() = 0; + + protected: + void RunImpl(); + + public: + void Run(FormatBufferType& format, ContextArgsInterface* argsInterface); + void Run(Detail::BufferInProperties& bufferInProperties, ContextArgsInterface* argsInterface) { return Run(static_cast(bufferInProperties), argsInterface); } + + public: + Detail::FormatIndex GetFormatIndexThrow(); + + public: + void FormatDataApplyNextOverride(); + + protected: + std::basic_string_view ParseNextOverrideFormatData(); + + void ParseFormatDataBase(); + void ParseFormatDataBase_ValueIntPrint(const typename Detail::ValueIntPrint type); + void ParseFormatDataSpecial(); + void ParseFormatDataSpecial_ShiftType(const typename Detail::ShiftType type); + void ParseFormatDataCustom(); + void ParseFormatData(); + + void ParseSpecial(); + void ParseVariable(typename Detail::FormatIndex formatIdx); + bool Parse(); + + protected: + virtual void ParseTimer() = 0; + virtual void ParseDate() = 0; + virtual void ParseSetter() = 0; + + public: + template void FormatReadParameterThrow(T& i, const T& defaultValue); + + public: + template + inline StringViewFormat GetStringViewParamUntil(CharToTest ...c) { + const char* namePos = m_Format.GetBufferCurrentPos(); + m_Format.ParamGoTo(c...); + return StringViewFormat(namePos, static_cast(m_Format.GetBufferCurrentPos() - namePos)); + } + + template + inline StringViewFormat GetStringViewUntil(CharToTest ...c) { + const char* namePos = m_Format.GetBufferCurrentPos(); + m_Format.GoTo(c...); + return StringViewFormat(namePos, static_cast(m_Format.GetBufferCurrentPos() - namePos)); + } + + inline typename Detail::DataType ReadDataType() + { + Detail::DataType res; + m_Format.ReadInt(res); + return res; + } + }; +} + +#include "TextPropertiesParserImpl.h" diff --git a/src/ProjectCore/FMT/Context/BasicContext/BasicContextCoreImpl.h b/src/ProjectCore/FMT/Context/BasicContext/BasicContextCoreImpl.h new file mode 100644 index 0000000..e1a2e21 --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/BasicContextCoreImpl.h @@ -0,0 +1,97 @@ +#pragma once + +#include "BasicContext.h" + +namespace ProjectCore::FMT::Context +{ + template + BasicContext::BasicContext(Detail::ITextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties) + : m_Format() + , m_ValuesIndex(0, 0) + , m_FormatData() + , m_ContextArgsInterface(nullptr) + , m_TextPropertiesParser(*this, textPropertiesExecutor, parentContextProperties) + {} + + template + void BasicContext::Terminate() + { + m_TextPropertiesParser.Terminate(); + } + + template + void BasicContext::RunImpl() + { + while (!m_Format.IsEnd()) + { + const CharFormat* beginContinousString = m_Format.GetBufferCurrentPos(); + std::size_t sizeContinousString = 0; + while (m_Format.IsEnd() == false && m_Format.IsEqualTo('{') == false) + { + ++sizeContinousString; + m_Format.Forward(); + } + FormatToParamsString(beginContinousString, sizeContinousString); + + if (m_Format.IsEnd() == false && m_Format.IsEqualTo('{')) + FormatExecParams(); + } + } + + template + void BasicContext::Run(FormatBufferType& format, ContextArgsInterface* argsInterface) + { + // Save old context + FormatBufferType oldFormat = m_Format; + ContextArgsInterface* oldArgsInterface = m_ContextArgsInterface; + Detail::FormatIndex oldValuesIndex = m_ValuesIndex; + Detail::TextProperties::Properties saveTextProperties = m_TextPropertiesParser.Save(); + // Set new context + m_Format = format; + m_ContextArgsInterface = argsInterface; + m_ValuesIndex = Detail::FormatIndex(0, static_cast(argsInterface->Size())); + SetArgsInterfaceCurrentContex(); + // Run + RunImpl(); + // Restore old context + m_Format = oldFormat; + m_ContextArgsInterface = oldArgsInterface; + m_ValuesIndex = oldValuesIndex; + m_TextPropertiesParser.Reload(saveTextProperties); + } + + template + template + void BasicContext::FormatReadParameterThrow(T& i, const T& defaultValue) { + if (!m_Format.IsEqualTo('{')) + { + if (m_Format.FastReadUInt(i) == false) + i = defaultValue; + return; + } + + // SubIndex + Detail::FormatIndex formatIdx = GetFormatIndexThrow(); + m_Format.IsEqualToForwardThrow('}'); + if constexpr (std::is_convertible_v) + i = static_cast(m_ContextArgsInterface->GetIntAt(formatIdx)); + else if constexpr (std::is_convertible_v) + i = static_cast(m_ContextArgsInterface->GetStringAt(formatIdx)); + + // FIXME WTF + // TRY const CharFormat* const mainSubFormat = m_Format.GetBufferCurrentPos(); + // CATCH m_Format.SetBufferCurrentPos(mainSubFormat); + } + + template + void BasicContext::FormatDataApplyNextOverride() { + if (m_FormatData.NextOverride.size() == 0) + return; + + FormatBufferType overrideAsFormat(m_FormatData.NextOverride); + FormatBufferType formatCopy = m_Format; + m_Format = overrideAsFormat; + ParseFormatData(); + m_Format = formatCopy; + } +} diff --git a/src/ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h b/src/ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h new file mode 100644 index 0000000..ba304be --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h @@ -0,0 +1,5 @@ +#pragma once + +#include "BasicContextParseImpl.h" +#include "BasicContext.h" +#include "BasicContextCoreImpl.h" diff --git a/src/ProjectCore/FMT/Context/BasicContext/BasicContextParseImpl.h b/src/ProjectCore/FMT/Context/BasicContext/BasicContextParseImpl.h new file mode 100644 index 0000000..3ebbd1c --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/BasicContextParseImpl.h @@ -0,0 +1,260 @@ +#pragma once + +#include "BasicContext.h" +#include "BasicContextCoreImpl.h" + +namespace ProjectCore::FMT::Context +{ + template + std::basic_string_view BasicContext::ParseNextOverrideFormatData() { + m_Format.IgnoreAllSpaces(); + m_Format.ParamGoTo('{', '=', ':'); + m_Format.IgnoreAllSpaces(); + m_Format.IsEqualToForward('=', ':'); + m_Format.IgnoreAllSpaces(); + m_Format.ParamGoTo('{'); + + const CharFormat* begin = m_Format.GetBufferCurrentPos(); + m_Format.IsEqualToForwardThrow('{'); + int scopes = 0; + while (m_Format.IsEndOfParameter() == false || scopes > 0) + { + m_Format.GoTo('\'', '}', '{'); + if (m_Format.IsEqualToForward('\'')) + m_Format.GoToForward('\''); + else if (m_Format.IsEqualToForward('{')) + scopes++; + else if (scopes > 0 && m_Format.IsEqualToForward('}')) + scopes--; + } + m_Format.IsEqualToForwardThrow('}'); + const CharFormat* end = m_Format.GetBufferCurrentPos(); + return std::basic_string_view(begin, end); + } + + template + void BasicContext::ParseFormatDataBase_ValueIntPrint(const typename Detail::ValueIntPrint type) { + m_FormatData.IntPrint = type; + if (m_Format.IsEqualToForward('#')) + m_FormatData.DigitSize.Value = Detail::DigitSize::MAX_DIGIT_SIZE; + else + FormatReadParameterThrow(m_FormatData.DigitSize.Value, Detail::DigitSize::DEFAULT); + } + + template + void BasicContext::ParseFormatDataBase() { + + if (m_Format.IsEqualToForward('C')) { m_TextPropertiesParser.ParseColor(); } + else if (m_Format.IsEqualToForward('S')) { m_TextPropertiesParser.ParseStyle(); } + else if (m_Format.IsEqualToForward('F')) { m_TextPropertiesParser.ParseFront(); } + + else if (m_Format.IsEqualToForward('B')) { ParseFormatDataBase_ValueIntPrint(Detail::ValueIntPrint::Bin); } + else if (m_Format.IsEqualToForward('X')) { ParseFormatDataBase_ValueIntPrint(Detail::ValueIntPrint::Hex); } + else if (m_Format.IsEqualToForward('O')) { ParseFormatDataBase_ValueIntPrint(Detail::ValueIntPrint::Oct); } + else if (m_Format.IsEqualToForward('D')) { ParseFormatDataBase_ValueIntPrint(Detail::ValueIntPrint::Dec); } + + else if (m_Format.IsEqualToForward('L')) { m_FormatData.PrintStyle = Detail::PrintStyle::LowerCase; } + else if (m_Format.IsEqualToForward('U')) { m_FormatData.PrintStyle = Detail::PrintStyle::UpperCase; } + + else if (m_Format.IsEqualToForward('A')) { m_FormatData.Safe = true; } + + else if (m_Format.IsEqualToForward('K')) { m_FormatData.KeepNewStyle = true; } + + else if (m_Format.IsEqualToForward('N')) { m_FormatData.NextOverride = ParseNextOverrideFormatData(); } + } + + template + void BasicContext::ParseFormatDataSpecial_ShiftType(const Detail::ShiftType type) { + m_FormatData.ShiftType = type; + FormatReadParameterThrow(m_FormatData.ShiftSize.Value, Detail::ShiftSize::DEFAULT); + if (m_Format.IsEqualToForward(':')) + { + m_FormatData.ShiftPrint.Before = m_Format.GetAndForward(); + m_FormatData.ShiftPrint.After = m_FormatData.ShiftPrint.Before; + if (m_Format.IsEqualToForward('|')) + m_FormatData.ShiftPrint.After = m_Format.GetAndForward(); + } + } + + template + void BasicContext::ParseFormatDataSpecial() { + if (m_Format.IsEqualToForward('{')) + { + Detail::FormatIndex formatIndex = GetFormatIndexThrow(); + if ((m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex)) + || m_FormatData.ModifyTestThrow(m_ContextArgsInterface->template GetTypeAtIndex(formatIndex))) == false) + throw Detail::FMTGivenTypeError{}; + m_Format.IsEqualToForwardThrow('}'); + } + else if (m_Format.IsEqualToForward('=')) { m_FormatData.TrueValue = true; } + + else if (m_Format.IsEqualToForward('.')) { FormatReadParameterThrow(m_FormatData.FloatPrecision.Value, Detail::FloatPrecision::DEFAULT); } + + else if (m_Format.IsEqualToForward('>')) { ParseFormatDataSpecial_ShiftType(Detail::ShiftType::Right); } + else if (m_Format.IsEqualToForward('<')) { ParseFormatDataSpecial_ShiftType(Detail::ShiftType::Left); } + else if (m_Format.IsEqualToForward('^')) { + if (m_Format.IsEqualToForward('<')) + ParseFormatDataSpecial_ShiftType(Detail::ShiftType::CenterLeft); + else { + m_Format.IsEqualToForward('>'); + ParseFormatDataSpecial_ShiftType(Detail::ShiftType::CenterRight); + } } + } + + template + void BasicContext::ParseFormatDataCustom() { + StringViewFormat name = GetStringViewParamUntil(' ', '=', '\'', '{', ','); + m_Format.ParamGoTo('=', '\'', '{', ','); + m_Format.IsEqualToForward('='); + m_Format.IgnoreAllSpaces(); + + if (m_Format.IsEqualToForward('\'')) { + StringViewFormat value = GetStringViewUntil('\''); + m_FormatData.AddSpecifier(name, value); + } + else if (m_Format.IsADigit()) { + Detail::DataType value = ReadDataType(); + m_FormatData.AddSpecifier(name, value); + } + else if (m_Format.IsEqualToForward('{')) { + [[maybe_unused]] Detail::FormatIndex idx = GetFormatIndexThrow(); + // FIXME + // m_FormatData.AddSpecifier(name, GetTypeAtIndexAuto(idx)); + m_Format.IsEqualToForward('}'); + } + else if (m_Format.IsEqualTo(',', '}')) { + m_FormatData.AddSpecifier(name); + } + } + + /////---------- Impl ----------///// + template + void BasicContext::ParseFormatData() + { + // ':' for classic use ; '{' for NextOverride + if (m_Format.IsEqualTo(':') || m_Format.IsEqualTo('{')) + { + m_FormatData.HasSpec = true; + while (!m_Format.IsEndOfParameter()) { + m_Format.Forward(); + m_Format.IgnoreAllSpaces(); + + if(m_Format.IsUpperCase()) + ParseFormatDataBase(); + else if(!m_Format.IsLowerCase()) + ParseFormatDataSpecial(); + else + ParseFormatDataCustom(); + + m_Format.ParamGoTo(','); + } + } + } + + template + Detail::FormatIndex BasicContext::GetFormatIndexThrow() { + const CharFormat* mainSubFormat = m_Format.GetBufferCurrentPos(); + + // I : if there is no number specified : ':' or '}' + if (m_Format.IsEqualTo(':') || m_Format.IsEqualTo('}')) + if(m_ValuesIndex.IsValid()) + return m_ValuesIndex.GetAndNext(); + + // II: A number(idx) + Detail::FormatIndex subIndex; + subIndex.SetContext(m_ValuesIndex); + if (m_Format.FastReadUInt(subIndex.Index)) + if (m_Format.IsEqualTo(':') || m_Format.IsEqualTo('}')) + if (subIndex.IsValid()) + return subIndex; + m_Format.SetBufferCurrentPos(mainSubFormat); + + // III : A name + Detail::FormatIndex indexOfNamedArg = m_ContextArgsInterface->GetIndexOfCurrentNameArg(); + indexOfNamedArg.SetContext(m_ValuesIndex); + if(indexOfNamedArg.IsValid()) + return indexOfNamedArg; + m_Format.SetBufferCurrentPos(mainSubFormat); + + // VI : { which is a idx to a number + if (m_Format.IsEqualToForward('{')) + { + Detail::FormatIndex recIndex = GetFormatIndexThrow(); + recIndex.SetContext(m_ValuesIndex); + + if(m_Format.IsEqualToForward('}') && recIndex.IsValid()) + { + m_Format.IgnoreAllSpaces(); + if (m_Format.IsEqualTo(':', '}')) + { + Detail::FormatIndex finalRecIndex = m_ContextArgsInterface->GetFormatIndexAt(recIndex); + finalRecIndex.SetContext(m_ValuesIndex); + if (finalRecIndex.IsValid()) + return finalRecIndex; + throw Detail::FMTIndexError{}; + } + } + } + m_Format.SetBufferCurrentPos(mainSubFormat); + return Detail::FormatIndex(); + } + + template + void BasicContext::ParseSpecial() + { + if (m_Format.IsEqualToForward('C')) { m_TextPropertiesParser.ParseColor(); } + else if (m_Format.IsEqualToForward('S')) { m_TextPropertiesParser.ParseStyle(); } + else if (m_Format.IsEqualToForward('F')) { m_TextPropertiesParser.ParseFront(); } + else if (m_Format.IsEqualToForward('T')) { ParseTimer(); } + else if (m_Format.IsEqualToForward('D')) { ParseDate(); } + else if (m_Format.IsEqualToForward('K')) { ParseSetter(); } + } + + template + void BasicContext::ParseVariable(Detail::FormatIndex formatIdx) { + FormatDataType saveFormatData = m_FormatData; + m_FormatData = FormatDataType{}; + Detail::TextProperties::Properties saveTextProperties = m_TextPropertiesParser.Save(); + + if (!m_FormatData.IsInit) + ParseFormatData(); + + m_ContextArgsInterface->RunTypeAtIndex(formatIdx); + + if (m_FormatData.KeepNewStyle == false) + m_TextPropertiesParser.Reload(saveTextProperties); + + m_FormatData = saveFormatData; + } + + template + bool BasicContext::Parse() { + m_Format.Forward(); // Skip { + + if (m_Format.IsUpperCase()) + { + ParseSpecial(); + m_Format.GoOutOfParameter(); // Skip } + return true; + } + + Detail::FormatIndex formatIdx = GetFormatIndexThrow(); + if (formatIdx.IsValid()) + { + ParseVariable(formatIdx); + m_Format.GoOutOfParameter(); // Skip } + return true; + } + + return false; + } +} + + diff --git a/src/ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h new file mode 100644 index 0000000..3ff8acd --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h @@ -0,0 +1,99 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + class ITextPropertiesExecutor + { + public: + virtual ~ITextPropertiesExecutor() = default; + + public: + virtual void AllPropertiesReset() = 0; + + public: + virtual void ResetColor() = 0; + virtual void ExecuteColor(const TextProperties::TextColor::BasicColorFG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::BasicColorBG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::BasicColor& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::Color24bFG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::Color24bBG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::Color24b& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::ColorCubeFG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::ColorCubeBG& t) = 0; + virtual void ExecuteColor(const TextProperties::TextColor::ColorCube& t) = 0; + + public: + virtual void ResetFront() = 0; + virtual void ExecuteFront(const TextProperties::TextFront::FrontID& t) = 0; + + public: + virtual void ResetStyle() = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Intensity& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Italic& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Underline& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::ColorCube& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color24b& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Blink& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Inverted& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Ideogram& t) = 0; + virtual void ExecuteStyle(const TextProperties::TextStyle::Script& t) = 0; + + virtual void ExecuteStyle(const TextProperties::TextStyle::BasicStyle& t) + { + switch(t) + { + case TextProperties::TextStyle::BasicStyle::Intensity_Bold: + case TextProperties::TextStyle::BasicStyle::Intensity_Dim: + case TextProperties::TextStyle::BasicStyle::Intensity_Normal: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Italic_Enable: + case TextProperties::TextStyle::BasicStyle::Italic_Disable: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Underline_Underlined: + case TextProperties::TextStyle::BasicStyle::Underline_DoubleUnerlined: + case TextProperties::TextStyle::BasicStyle::Underline_Disable: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Underline_SelectColor: + break; + + case TextProperties::TextStyle::BasicStyle::Blink_SlowBlink: + case TextProperties::TextStyle::BasicStyle::Blink_FastBlink: + case TextProperties::TextStyle::BasicStyle::Blink_Disable: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Inverted_Enable: + case TextProperties::TextStyle::BasicStyle::Inverted_Disable: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Ideogram_Underlined: + case TextProperties::TextStyle::BasicStyle::Ideogram_DoubleUnderlined: + case TextProperties::TextStyle::BasicStyle::Ideogram_Overlined: + case TextProperties::TextStyle::BasicStyle::Ideogram_DoubleOverlined: + case TextProperties::TextStyle::BasicStyle::Ideogram_StressMarking: + case TextProperties::TextStyle::BasicStyle::Ideogram_AllDisable: + ExecuteStyle(static_cast(t)); + break; + + case TextProperties::TextStyle::BasicStyle::Script_Superscript: + case TextProperties::TextStyle::BasicStyle::Script_Subscript: + case TextProperties::TextStyle::BasicStyle::Script_AllDisable: + ExecuteStyle(static_cast(t)); + break; + + default: + break; + } + } + }; +} diff --git a/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParser.h b/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParser.h new file mode 100644 index 0000000..51dd315 --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParser.h @@ -0,0 +1,168 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ITextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BasicTextPropertiesParser + { + public: + BasicTextPropertiesParser(BasicContext& context, ITextPropertiesExecutor& textPropertiesExecutor, const TextProperties::Properties* baseContextProperties) + : m_Context{context} + , m_TextPropertiesExecutor{textPropertiesExecutor} + , m_BaseContextProperties{baseContextProperties} + , m_CurrentContextProperties{baseContextProperties == nullptr ? TextProperties::Properties{} : *baseContextProperties} + {} + + void Terminate() + { + ReloadDefault(); + } + + public: + template + void ColorModif(const T& modif) + { + m_CurrentContextProperties.Color.ModifyThrow(modif); + m_TextPropertiesExecutor.ExecuteColor(modif); + } + template + void StyleModif(const T& modif) + { + m_CurrentContextProperties.Style.ModifyThrow(modif); + m_TextPropertiesExecutor.ExecuteStyle(modif); + } + template + void FrontModif(const T& modif) + { + m_CurrentContextProperties.Front.ModifyThrow(modif); + m_TextPropertiesExecutor.ExecuteFront(modif); + } + + void AllPropertiesReset() + { + ColorModifReset(); + StyleModifReset(); + FrontModifReset(); + } + void ColorModifReset() + { + m_CurrentContextProperties.Color.ModifyReset(); + m_TextPropertiesExecutor.ResetColor(); + } + void StyleModifReset() + { + m_CurrentContextProperties.Style.ModifyReset(); + m_TextPropertiesExecutor.ResetStyle(); + } + void FrontModifReset() + { + m_CurrentContextProperties.Front.ModifyReset(); + m_TextPropertiesExecutor.ResetFront(); + } + + public: + void ColorExecuteOnIndex(const FormatIndex& index); + void StyleExecuteOnIndex(const FormatIndex& index); + void FrontExecuteOnIndex(const FormatIndex& index); + + public: + void ParseColor(); + template + bool GetColorCode(T& t); + + void ParseStyle(); + TextProperties::TextStyle::BasicStyle GetStyleCode(); + TextProperties::TextStyle::UnderlineColor::ColorCube SelectUnderlinedColorStyle(); + + void ParseFront(); + + public: + TextProperties::Properties Save() { return m_CurrentContextProperties; } + + public: + void ReloadDefault() { ReloadDefaultColor(); ReloadDefaultStyle(); ReloadDefaultFront(); } + void ReloadDefaultColor() { ReloadDefaultColorFG(); ReloadDefaultColorBG(); } + void ReloadDefaultColorFG() { if (m_BaseContextProperties != nullptr) return ReloadColorFG(m_BaseContextProperties->Color.Fg); return ReloadColorFG(TextProperties::TextColor::ColorFG{}); } + void ReloadDefaultColorBG() { if (m_BaseContextProperties != nullptr) return ReloadColorBG(m_BaseContextProperties->Color.Bg); return ReloadColorBG(TextProperties::TextColor::ColorBG{}); } + void ReloadDefaultStyle() { if (m_BaseContextProperties != nullptr) return ReloadStyle(m_BaseContextProperties->Style); return ReloadStyle(TextProperties::TextStyle::Style{}); } + void ReloadDefaultFront() { if (m_BaseContextProperties != nullptr) return ReloadFront(m_BaseContextProperties->Front); return ReloadFront(TextProperties::TextFront::Front{}); } + + void Reload(const TextProperties::Properties& target) { ReloadColor(target.Color); ReloadStyle(target.Style); ReloadFront(target.Front); } + void ReloadColor(const TextProperties::TextColor::Color& target) { ReloadColorFG(target.Fg); ReloadColorBG(target.Bg); } + void ReloadColorFG(const TextProperties::TextColor::ColorFG& target); + void ReloadColorBG(const TextProperties::TextColor::ColorBG& target); + void ReloadStyle(const TextProperties::TextStyle::Style& target); + void ReloadFront(const TextProperties::TextFront::Front& target); + + public: + ITextPropertiesExecutor& GetTextPropertiesExecutor() { return m_TextPropertiesExecutor; } + const TextProperties::Properties* GetBaseContextProperties() { return m_BaseContextProperties; } + TextProperties::Properties& GetCurrentContextProperties() { return m_CurrentContextProperties; } + + private: + BasicContext& m_Context; + ITextPropertiesExecutor& m_TextPropertiesExecutor; + const TextProperties::Properties* m_BaseContextProperties; + TextProperties::Properties m_CurrentContextProperties; + + public: + template + inline void AskColorModif(const T& modif) { if (m_CurrentContextProperties.Color.NeedModif(modif)) ColorModif(modif); } + template + inline void AskStyleModif(const T& modif) { if (m_CurrentContextProperties.Style.NeedModif(modif)) StyleModif(modif); } + template + inline void AskFrontModif(const T& modif) { if (m_CurrentContextProperties.Front.NeedModif(modif)) FrontModif(modif); } + + void AskColorModif(const TextProperties::TextColor::BasicColor modif) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif); + return ColorModif(modif.Fg); + } + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif.Bg); + } + + void AskColorModif(const TextProperties::TextColor::ColorCube& modif) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif); + return ColorModif(modif.Fg); + } + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif.Bg); + } + + void AskColorModif(const TextProperties::TextColor::Color24b& modif) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + { + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif); + return ColorModif(modif.Fg); + } + if (m_CurrentContextProperties.Color.NeedModif(modif.Fg)) + return ColorModif(modif.Bg); + } + + void AskColorModif(const TextProperties::TextColor::ColorFG modif) + { + ReloadColorFG(modif); + } + void AskColorModif(const TextProperties::TextColor::ColorBG modif) + { + ReloadColorBG(modif); + } + void AskColorModif(const TextProperties::TextColor::Color& modif) + { + ReloadColor(modif); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParserImpl.h b/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParserImpl.h new file mode 100644 index 0000000..5285f1c --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/TextPropertiesParserImpl.h @@ -0,0 +1,357 @@ +#pragma once + +#include "TextPropertiesParser.h" + +namespace ProjectCore::FMT::Detail +{ + template + void BasicTextPropertiesParser::ColorExecuteOnIndex(const FormatIndex& index) + { + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextColor::Color& data) { this->ReloadColor(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextColor::BasicColorFG& data) { this->AskColorModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextColor::BasicColorBG& data) { this->AskColorModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const Detail::TextProperties::TextColor::ColorCubeFG& data) { this->AskColorModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const Detail::TextProperties::TextColor::ColorCubeBG& data) { this->AskColorModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const Detail::TextProperties::TextColor::Color24bFG& data) { this->AskColorModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const Detail::TextProperties::TextColor::Color24bBG& data) { this->AskColorModif(data); } ); + } + + template + void BasicTextPropertiesParser::FrontExecuteOnIndex(const FormatIndex& index) + { + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextFront::Front& data) { this->ReloadFront(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextFront::FrontID& data) { this->AskFrontModif(data); } ); + } + + template + void BasicTextPropertiesParser::StyleExecuteOnIndex(const FormatIndex& index) + { + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Style& data) { this->ReloadStyle(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Intensity& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Italic& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Underline& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Blink& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Inverted& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Ideogram& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::Script& data) { this->AskStyleModif(data); } ); + + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::UnderlineColor::ColorCube& data) { this->AskStyleModif(data); } ); + m_Context.GetContextArgsInterface().template RunFuncFromTypeAtIndex( index, [this](const TextProperties::TextStyle::UnderlineColor::Color24b& data) { this->AskStyleModif(data); } ); + } + + template + void BasicTextPropertiesParser::ParseColor() + { + if (m_Context.Format().IsEqualToForward(':')) { + m_Context.Format().IgnoreAllSpaces(); + if (m_Context.Format().IsEqualToForward('{')) + { + FormatIndex idx = m_Context.GetFormatIndexThrow(); + ColorExecuteOnIndex(idx); + m_Context.Format().IsEqualToForward('}'); + } + else + { + TextProperties::TextColor::BasicColorFG colorFg; + bool colorFgFound = GetColorCode(colorFg); + + m_Context.Format().ParamGoTo('-', ','); + if (m_Context.Format().IsEqualToForward('-')) { + m_Context.Format().IgnoreAllSpaces(); + TextProperties::TextColor::BasicColorBG colorBg; + bool colorBgFound = GetColorCode(colorBg); + if (colorBgFound && colorFgFound) + AskColorModif(TextProperties::TextColor::BasicColor{ colorFg, colorBg }); + else + ReloadDefaultColor(); + } + else + { + if (colorFgFound) + AskColorModif(colorFg); + else + ReloadDefaultColor(); + } + } + } + else + ReloadDefaultColor(); + } + + template + template + bool BasicTextPropertiesParser::GetColorCode(T& t) + { + static constexpr std::string_view colorCode[] = { + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + " ", + "default" + }; + + std::uint8_t step = static_cast(m_Context.Format().IsEqualToForward('+') ? T::BaseBStep : T::BaseStep); + std::uint8_t code = static_cast(m_Context.Format().GetWordFromList(colorCode)); + if (code == m_Context.Format().GET_WORD_FROM_LIST_NOT_FOUND) return false; + t = static_cast(code + step); + return true; + } + + template + void BasicTextPropertiesParser::ParseStyle() + { + if (m_Context.Format().IsEqualToForward(':')) { + if (!m_Context.Format().IsEqualTo('}', ',')) { + bool l = true; + while (l) { + m_Context.Format().IgnoreAllSpaces(); + if (m_Context.Format().IsEqualToForward('{')) + { + FormatIndex idx = m_Context.GetFormatIndexThrow(); + StyleExecuteOnIndex(idx); + m_Context.Format().IsEqualToForward('}'); + } + else + { + TextProperties::TextStyle::BasicStyle style = GetStyleCode(); + if (style == TextProperties::TextStyle::BasicStyle::Underline_SelectColor) + { + TextProperties::TextStyle::UnderlineColor::ColorCube underlineColor = SelectUnderlinedColorStyle(); + StyleModif(underlineColor); + } + else + StyleModif(style); + } + m_Context.Format().ParamGoTo('|', ','); + l = m_Context.Format().IsEqualToForward('|'); + m_Context.Format().IgnoreAllSpaces(); + } + } + else + ReloadDefaultStyle(); + } + else + ReloadDefaultStyle(); + } + + template + TextProperties::TextStyle::BasicStyle BasicTextPropertiesParser::GetStyleCode() + { + using FormatType = typename BasicContext::FormatBufferType; + static constexpr typename FormatType::template TextTo styleCode[] = { + { "bold", TextProperties::TextStyle::BasicStyle::Intensity_Bold }, + { "dim", TextProperties::TextStyle::BasicStyle::Intensity_Dim }, + { "n-intensity", TextProperties::TextStyle::BasicStyle::Intensity_Normal }, + { "italic", TextProperties::TextStyle::BasicStyle::Italic_Enable }, + { "n-italic", TextProperties::TextStyle::BasicStyle::Italic_Disable }, + { "underlined", TextProperties::TextStyle::BasicStyle::Underline_Underlined }, + { "d-underlined", TextProperties::TextStyle::BasicStyle::Underline_DoubleUnerlined }, + { "n-underlined", TextProperties::TextStyle::BasicStyle::Underline_Disable }, + { "c-underlined", TextProperties::TextStyle::BasicStyle::Underline_SelectColor }, + { "slowblink", TextProperties::TextStyle::BasicStyle::Blink_SlowBlink }, + { "fastblink", TextProperties::TextStyle::BasicStyle::Blink_FastBlink }, + { "n-blink", TextProperties::TextStyle::BasicStyle::Blink_Disable }, + { "inverted", TextProperties::TextStyle::BasicStyle::Inverted_Enable }, + { "n-inverted", TextProperties::TextStyle::BasicStyle::Inverted_Disable }, + { "i-underlined", TextProperties::TextStyle::BasicStyle::Ideogram_Underlined }, + { "i-d-underlined", TextProperties::TextStyle::BasicStyle::Ideogram_DoubleUnderlined }, + { "i-overlined", TextProperties::TextStyle::BasicStyle::Ideogram_Overlined }, + { "i-d-overlined", TextProperties::TextStyle::BasicStyle::Ideogram_DoubleOverlined }, + { "i-stress", TextProperties::TextStyle::BasicStyle::Ideogram_StressMarking }, + { "n-i", TextProperties::TextStyle::BasicStyle::Ideogram_AllDisable }, + { "superscript", TextProperties::TextStyle::BasicStyle::Script_Superscript }, + { "subscript", TextProperties::TextStyle::BasicStyle::Script_Subscript }, + { "n-script", TextProperties::TextStyle::BasicStyle::Script_AllDisable } + }; + + return m_Context.Format().GetWordFromList(styleCode); + } + + template + TextProperties::TextStyle::UnderlineColor::ColorCube BasicTextPropertiesParser::SelectUnderlinedColorStyle() + { + m_Context.Format().ParamGoTo(':'); + m_Context.Format().IsEqualToForward(':'); + m_Context.Format().IgnoreAllSpaces(); + TextProperties::TextStyle::UnderlineColor::ColorCube color; + if (GetColorCode(color)) return color; + // TODO : handle Color24b + if (m_BaseContextProperties != nullptr) + return m_BaseContextProperties->Style.UnderlineColor.Data.ColorCube; + return TextProperties::TextStyle::UnderlineColor::ColorCube{}; + } + + + + template + void BasicTextPropertiesParser::ParseFront() + { + static constexpr std::string_view frontCode[] = { + "default", + "front0", + "front1", + "front2", + "front3", + "front4", + "front5", + "front6", + "front7", + "front8", + "front9" + }; + + if (m_Context.Format().IsEqualToForward(':')) + { + m_Context.Format().IgnoreAllSpaces(); + TextProperties::TextFront::FrontID frontID = (static_cast(m_Context.Format().GetWordFromList(frontCode))); + FrontModif(frontID); + } + else + ReloadDefaultFront(); + } + + template + void BasicTextPropertiesParser::ReloadColorFG(const TextProperties::TextColor::ColorFG& target) + { + if (target.Type != m_CurrentContextProperties.Color.Fg.Type) + { + switch (target.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: + ColorModif(target.Data.BasicColor); + break; + case TextProperties::TextColor::ColorType::ColorCube: + ColorModif(target.Data.ColorCube); + break; + case TextProperties::TextColor::ColorType::Color24b: + ColorModif(target.Data.Color24b); + break; + } + } + else + { + switch (target.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: + if (m_CurrentContextProperties.Color.Fg.Data.BasicColor != target.Data.BasicColor) + ColorModif(target.Data.BasicColor); + break; + case TextProperties::TextColor::ColorType::ColorCube: + if (m_CurrentContextProperties.Color.Fg.Data.ColorCube != target.Data.ColorCube) + ColorModif(target.Data.ColorCube); + break; + case TextProperties::TextColor::ColorType::Color24b: + if (m_CurrentContextProperties.Color.Fg.Data.Color24b != target.Data.Color24b) + ColorModif(target.Data.Color24b); + break; + } + } + } + + template + void BasicTextPropertiesParser::ReloadColorBG(const TextProperties::TextColor::ColorBG& target) + { + if (target.Type != m_CurrentContextProperties.Color.Bg.Type) + { + switch (target.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: + ColorModif(target.Data.BasicColor); + break; + case TextProperties::TextColor::ColorType::ColorCube: + ColorModif(target.Data.ColorCube); + break; + case TextProperties::TextColor::ColorType::Color24b: + ColorModif(target.Data.Color24b); + break; + } + } + else + { + switch (target.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: + if (m_CurrentContextProperties.Color.Bg.Data.BasicColor != target.Data.BasicColor) + ColorModif(target.Data.BasicColor); + break; + case TextProperties::TextColor::ColorType::ColorCube: + if (m_CurrentContextProperties.Color.Bg.Data.ColorCube != target.Data.ColorCube) + ColorModif(target.Data.ColorCube); + break; + case TextProperties::TextColor::ColorType::Color24b: + if (m_CurrentContextProperties.Color.Bg.Data.Color24b != target.Data.Color24b) + ColorModif(target.Data.Color24b); + break; + } + } + } + + template + void BasicTextPropertiesParser::ReloadStyle(const TextProperties::TextStyle::Style& target) + { + if (target.Intensity != m_CurrentContextProperties.Style.Intensity) { StyleModif(target.Intensity); m_CurrentContextProperties.Style.Intensity = target.Intensity; } + if (target.Italic != m_CurrentContextProperties.Style.Italic) { StyleModif(target.Italic); m_CurrentContextProperties.Style.Italic = target.Italic; } + if (target.Blink != m_CurrentContextProperties.Style.Blink) { StyleModif(target.Blink); m_CurrentContextProperties.Style.Blink = target.Blink; } + if (target.Inverted != m_CurrentContextProperties.Style.Inverted) { StyleModif(target.Inverted); m_CurrentContextProperties.Style.Inverted = target.Inverted; } + if (target.Ideogram != m_CurrentContextProperties.Style.Ideogram) { StyleModif(target.Ideogram); m_CurrentContextProperties.Style.Ideogram = target.Ideogram; } + if (target.Script != m_CurrentContextProperties.Style.Script) { StyleModif(target.Script); m_CurrentContextProperties.Style.Script = target.Script; } + + if (target.Underline != m_CurrentContextProperties.Style.Underline) { StyleModif(target.Underline); m_CurrentContextProperties.Style.Underline = target.Underline; } + + if (target.UnderlineColor.Type != m_CurrentContextProperties.Style.UnderlineColor.Type) + { + switch (target.UnderlineColor.Type) + { + case TextProperties::TextStyle::UnderlineColor::ColorType::Default: + StyleModif(TextProperties::TextStyle::UnderlineColor::ColorCube{ TextProperties::TextStyle::UnderlineColor::ColorCube::Default }); + break; + case TextProperties::TextStyle::UnderlineColor::ColorType::ColorCube: + StyleModif(target.UnderlineColor.Data.ColorCube); + m_CurrentContextProperties.Style.UnderlineColor.Data.ColorCube = target.UnderlineColor.Data.ColorCube; + break; + case TextProperties::TextStyle::UnderlineColor::ColorType::Color24b: + StyleModif(target.UnderlineColor.Data.Color24b); + m_CurrentContextProperties.Style.UnderlineColor.Data.Color24b = target.UnderlineColor.Data.Color24b; + break; + } + m_CurrentContextProperties.Style.UnderlineColor.Type = target.UnderlineColor.Type; + } + else + { + switch (target.UnderlineColor.Type) + { + case TextProperties::TextStyle::UnderlineColor::ColorType::Default: + break; + case TextProperties::TextStyle::UnderlineColor::ColorType::ColorCube: + if (m_CurrentContextProperties.Style.UnderlineColor.Data.ColorCube != target.UnderlineColor.Data.ColorCube) + { + StyleModif(target.UnderlineColor.Data.ColorCube); + m_CurrentContextProperties.Style.UnderlineColor.Data.ColorCube = target.UnderlineColor.Data.ColorCube; + } + break; + case TextProperties::TextStyle::UnderlineColor::ColorType::Color24b: + if (m_CurrentContextProperties.Style.UnderlineColor.Data.Color24b != target.UnderlineColor.Data.Color24b) + { + StyleModif(target.UnderlineColor.Data.Color24b); + m_CurrentContextProperties.Style.UnderlineColor.Data.Color24b = target.UnderlineColor.Data.Color24b; + } + break; + } + } + } + + template + void BasicTextPropertiesParser::ReloadFront(const TextProperties::TextFront::Front& target) + { + if (m_CurrentContextProperties.Front == target) + return; + + FrontModif(target.CurrentID); + m_CurrentContextProperties.Front = target; + } +} diff --git a/src/ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h b/src/ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h new file mode 100644 index 0000000..6b2be20 --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h @@ -0,0 +1,106 @@ + +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "FMTContextTemplate.h" + +#include +#include + +namespace ProjectCore::FMT::Detail +{ + template + class BasicArgsTupleInterface + { + public: + BasicArgsTupleInterface() {} + virtual ~BasicArgsTupleInterface() = default; + + public: + virtual size_t Size() = 0; + virtual void SetContext(std::any context) = 0; + + public: + virtual void RunTypeAtIndex(Detail::FormatIndex idx) = 0; + virtual Detail::FormatIndex GetIndexOfCurrentNameArg() = 0; + + virtual std::any GetTypeAtIndexImpl(Detail::FormatIndex idx) = 0; + + virtual Detail::FormatIndex GetFormatIndexAt(Detail::FormatIndex idx) = 0; + virtual typename std::basic_string_view GetStringAt(Detail::FormatIndex idx) = 0; + virtual int64_t GetIntAt(Detail::FormatIndex idx) = 0; + + virtual void RunFuncAtImpl(Detail::FormatIndex idx, std::function func) = 0; + + public: + template + const T* GetTypeAtIndex(Detail::FormatIndex idx) + { + try + { + return std::any_cast(GetTypeAtIndexImpl(idx)); + } + catch(...) + { + return nullptr; + } + } + + template + const T& GetTypeAtIndexThrow(Detail::FormatIndex idx) + { + const T* value = GetTypeAtIndex(idx); + if (value != nullptr) + return *value; + throw FMTGivenTypeError{}; + } + + + template + void RunFuncFromTypeAtIndex(Detail::FormatIndex idx, std::function func) + { + const T* value = GetTypeAtIndex(idx); + if (value != nullptr) + func(*value); + } + }; + + template + class BasicContextArgsTupleInterface : public BasicArgsTupleInterface + { + public: + BasicContextArgsTupleInterface() + : m_Context(nullptr) + {} + ~BasicContextArgsTupleInterface() override = default; + + public: + void SetContext(std::any context) override { m_Context = std::any_cast(context); } + + protected: + Context* m_Context; + }; + + template + class EmptyContextArgsTupleInterface : public BasicContextArgsTupleInterface + { + public: + EmptyContextArgsTupleInterface() {} + ~EmptyContextArgsTupleInterface() override = default; + + public: + size_t Size() override { return 0; } + + void RunTypeAtIndex(Detail::FormatIndex) override { } + + Detail::FormatIndex GetIndexOfCurrentNameArg() override { return Detail::FormatIndex{}; } + + std::any GetTypeAtIndexImpl(Detail::FormatIndex) override { return {}; } + + void RunFuncAtImpl(Detail::FormatIndex, std::function) override { } + + Detail::FormatIndex GetFormatIndexAt(Detail::FormatIndex) override { return Detail::FormatIndex{}; } + typename Context::StringViewFormat GetStringAt(Detail::FormatIndex) override { return ""; } + std::int64_t GetIntAt(Detail::FormatIndex) override { return 0; } + }; +} diff --git a/src/ProjectCore/FMT/Context/BasicContext/Utils/FMTContextTemplate.h b/src/ProjectCore/FMT/Context/BasicContext/Utils/FMTContextTemplate.h new file mode 100644 index 0000000..8b277c3 --- /dev/null +++ b/src/ProjectCore/FMT/Context/BasicContext/Utils/FMTContextTemplate.h @@ -0,0 +1,63 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + template + struct FormatTypeForwardAs + { + using Type = T; + }; + + template + struct FMTContextConvert + { + static constexpr bool IsConvertible = false; + }; + + template + requires (std::is_convertible_v && std::is_convertible_v) + struct FMTContextConvert + { + static constexpr bool IsConvertible = true; + static constexpr To Convert(const From& from) { return static_cast(from); } + }; + + template + requires (std::is_convertible_v && std::is_convertible_v) + struct FMTContextConvert + { + static constexpr bool IsConvertible = true; + static constexpr Detail::FormatIndex Convert(const From& from) { return Detail::FormatIndex(static_cast(from)); } + }; + + template + concept FMTCanContextConvert = requires(const From& from) + { + requires FMTContextConvert::IsConvertible; + { FMTContextConvert::Convert(from) } -> std::same_as; + }; + + //------------------------------------------------------------------------ + + template + struct FMTContextSame + { + static constexpr bool SameAs = false; + }; + + template + requires (std::is_same_v, Detail::GetBaseType>) + struct FMTContextSame + { + static constexpr bool SameAs = true; + }; + + template + concept FMTIsContextSame = requires(To* to, const From& from) + { + requires FMTContextSame::SameAs; + *to = from; + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/BaseFormat.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/BaseFormat.h new file mode 100644 index 0000000..0441563 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/BaseFormat.h @@ -0,0 +1,372 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" +#include "FormatterForwarders.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType { + static void Format(const typename FormatterContext::FormatSpecifierType& specifier, FormatterContext& context) { + if(specifier.ValueIsText) + context.SubContextArrayFMT("{ '{}', '{}' }", specifier.Name, specifier.ValueAsText); + else + context.SubContextArrayFMT("{ '{}', '{}' }", specifier.Name, specifier.ValueAsNumber); + } + }; + + template + struct FormatterType { + static void Format(const typename FormatterContext::DataType&, FormatterContext& context) { + context.SubContextArrayFMT("{:C:red}", "Missing '{' or '}' because currently the format data is used as a parameter"); + } + }; + + // Bool + template + struct FormatterType { + static void Format(const bool t, FormatterContext& context) { + if (!context.GetFormatData().TrueValue) { + if (t == true) context.BufferOut().FastWriteCharArray("True"); + else context.BufferOut().FastWriteCharArray("False"); + } else { + if (t == true) context.BufferOut().PushBack('1'); + else context.BufferOut().PushBack('0'); + } + } + }; + + // Int Types +#ifdef FMT_USE_STD_INTEGER + template + struct FormatterType { + static inline void Format(const std::int8_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::int16_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::int32_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::int64_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; +#else + template + struct FormatterType { + static inline void Format(const signed char t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const short t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const int t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const long t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const long long t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; +#endif + + // UInt Types +#ifdef FMT_USE_STD_INTEGER + template + struct FormatterType { + static inline void Format(const std::uint8_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::uint16_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::uint32_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const std::uint64_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; +#else + template + struct FormatterType { + static inline void Format(const unsigned char t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const unsigned short t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const unsigned int t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const unsigned long t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const unsigned long long t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; +#endif + + + + // Float Types + template + struct FormatterType { + static inline void Format(const float t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const double t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static inline void Format(const long double t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + + + + + template + struct FormatterType { + inline static void Format(const char t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + inline static void Format(const wchar_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + inline static void Format(const char8_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + inline static void Format(const char16_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + inline static void Format(const char32_t t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType { + static void Format(const char (&t)[SIZE], FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const wchar_t(&t)[SIZE], FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char8_t(&t)[SIZE], FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char16_t(&t)[SIZE], FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char32_t(&t)[SIZE], FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType { + static void Format(const char* const t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const wchar_t* const t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char8_t* const t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char16_t* const t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + template + struct FormatterType { + static void Format(const char32_t* const t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t, context); + } + }; + + + + //------------------ Pointer/Array of Type ------------------// + + template + struct FormatterType + { + static void Format(const void* const t, FormatterContext& context) { + if (t == nullptr) + return context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("null", "nullptr")); + + if (context.GetFormatData().IntPrint == Detail::ValueIntPrint::Hex) + return context.SubContextArrayFMT("{:X,=,U}", reinterpret_cast(t)); + else + return FormatterType, FormatterContext>::Format(reinterpret_cast(t), context); + } + }; + + template + struct FormatterType + { + static void Format(const T* const t, FormatterContext& context) { + + auto size = context.GetFormatData().GetSpecifierAsNumber("size", Detail::FORMAT_DATA_NOT_SPECIFIED); + + if(size == Detail::FORMAT_DATA_NOT_SPECIFIED) + { + if (context.GetFormatData().TrueValue) + { + if (context.GetFormatData().IntPrint == Detail::ValueIntPrint::Hex) + return context.SubContextArrayFMT("{:X,=,U}", reinterpret_cast(t)); + else + return FormatterType, FormatterContext>::Format(reinterpret_cast(t), context); + } + else + { + bool all = context.GetFormatData().HasSpecifier("size"); + if (all) + { + if (t == nullptr) + return context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("null", "nullptr")); + return context.SubContextArrayFMT("{} -> {:{}}", static_cast(t), *t, context.ForwardFormatData()); + } + else + return context.WriteType(*t); + } + return; + } + + if (t == nullptr) + return context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("null", "nullptr")); + + context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("begin", STDEnumerableUtility::DefaultBegin)); + + const auto& join = context.GetFormatData().GetSpecifierAsText("join", STDEnumerableUtility::DefaultJoin); + + auto beginValue = context.GetFormatData().GetSpecifierAsNumber("begin", 0); + + bool first = true; + const T* begin = t + beginValue; + const T* end = begin + size; + + while (begin < end) { + if (first) first = false; + else context.BufferOut().WriteIndentStringView(join); + context.WriteType(*begin++); + } + + context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("end", STDEnumerableUtility::DefaultEnd)); + } + }; + + template + struct FormatterType + { + static void Format(T const (&t)[SIZE], FormatterContext& context) { + + context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("begin", STDEnumerableUtility::DefaultBegin)); + + const auto& join = context.GetFormatData().GetSpecifierAsText("join", STDEnumerableUtility::DefaultJoin); + + bool first = true; + std::size_t beginValue = (std::size_t)context.GetFormatData().GetSpecifierAsNumber("begin", 0); + const T* begin = t + beginValue; + // FIXME : all thoses static_cast for size of string are dangerous + const T* end = begin + context.GetFormatData().GetSpecifierAsNumber("size", static_cast(SIZE - beginValue)); + + while(begin < end) + { + if (first) first = false; + else context.BufferOut().WriteIndentStringView(join); + context.WriteType(*begin++); + } + + context.BufferOut().FastWriteStringView(context.GetFormatData().GetSpecifierAsText("end", STDEnumerableUtility::DefaultEnd)); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatChrono.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatChrono.h new file mode 100644 index 0000000..838b928 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatChrono.h @@ -0,0 +1,172 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" +#include + +namespace ProjectCore::FMT::ChronoDetail +{ + template + void WriteSubTimeFull(const std::chrono::time_point& value, PatternFormat& pattern, FormatterContext& context) { + Detail::ShiftSize nbDigit{}; + pattern.FastReadUInt(nbDigit.Value); + + if (pattern.IsSameSeqForward('n', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('u', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('m', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('s')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('m')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('h')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + } + + template + void WriteSubTimeMod(const std::chrono::time_point& value, PatternFormat& pattern, FormatterContext& context) { + Detail::ShiftSize nbDigit; + pattern.FastReadUInt(nbDigit.Value); + bool isDefault = nbDigit.IsDefault(); + + if (isDefault) nbDigit.Value = 3; + if (pattern.IsSameSeqForward('n', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 1000), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('u', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 1000), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('m', 's')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 1000), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (isDefault) nbDigit.Value = 2; + if (pattern.IsSameSeqForward('s')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 60), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('m')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 60), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('h')) return context.BufferOut().WriteUInt(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count() % 24), Detail::ShiftType::Right, nbDigit, Detail::ShiftPrint_Zeros); + } + + template + void WriteSubTimeSub([[maybe_unused]] const std::chrono::time_point& value, [[maybe_unused]] PatternFormat& pattern, [[maybe_unused]] FormatterContext& context) { + Detail::ShiftSize nbDigit{}; + pattern.ReadUInt(nbDigit.Value); + + Detail::FloatPrecision nbDecimal{}; + if (pattern.IsEqualToForward('.')) + pattern.ReadUInt(nbDecimal.Value); + + if (pattern.IsSameSeqForward('u', 's')) return context.BufferOut().WriteFloat(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()) / 1000, nbDecimal, Detail::ShiftType::Right, nbDigit.Value + 1 + nbDecimal.Value, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('m', 's')) return context.BufferOut().WriteFloat(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()) / 1000000, nbDecimal, Detail::ShiftType::Right, nbDigit.Value + 1 + nbDecimal.Value, Detail::ShiftPrint_Zeros); + if (pattern.IsSameSeqForward('s')) return context.BufferOut().WriteFloat(static_cast(std::chrono::time_point_cast(value).time_since_epoch().count()) / 1000000000, nbDecimal, Detail::ShiftType::Right, nbDigit.Value + 1 + nbDecimal.Value, Detail::ShiftPrint_Zeros); + } + + template + bool WriteTime(const std::chrono::time_point& value, FormatterContext& context, bool useDefaultPattern = true) { + auto patternPtr = context.GetFormatData().GetSpecifierOnlyText("pattern"); + if (patternPtr == nullptr && useDefaultPattern == false) + return false; + + std::basic_string_view patternStr = "%h:%m:%s.%ms"; + + if (patternPtr != nullptr) + patternStr = patternPtr->ValueAsText; + + Detail::FMTFormatBuffer pattern(patternStr.data(), patternStr.size()); + context.BufferOut().FastWriteStringView(pattern.ParamGoToAndGetStr('%', '#', '/')); + while (!pattern.IsEnd()) { + + if (pattern.IsEqualToForward('%')) WriteSubTimeMod(value, pattern, context); + else if (pattern.IsEqualToForward('#')) WriteSubTimeFull(value, pattern, context); + else if (pattern.IsEqualToForward('/')) WriteSubTimeSub(value, pattern, context); + + context.BufferOut().FastWriteStringView(pattern.ParamGoToAndGetStr('%', '#', '/')); + } + + return true; + } +} + + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::chrono::time_point& t, FormatterContext& context) { + ChronoDetail::WriteTime(t, context); + } + }; + +#ifdef UTILITIES_COMPILER_MSVC + template + struct FormatterType, FormatterContext> + { + static void Format(const std::chrono::time_point& t, FormatterContext& context) { + ChronoDetail::WriteTime(t, context); + } + }; +#endif + + template + struct FormatterType + { + static void Format(const std::chrono::seconds& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('s'); + } + } + }; + + template + struct FormatterType + { + static void Format(const std::chrono::minutes& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('m'); + } + } + }; + + template + struct FormatterType + { + static void Format(const std::chrono::hours& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('h'); + } + } + }; + + template + struct FormatterType + { + static void Format(const std::chrono::milliseconds& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('m'); + context.BufferOut().PushBack('s'); + } + } + }; + + template + struct FormatterType + { + static void Format(const std::chrono::microseconds& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('u'); + context.BufferOut().PushBack('s'); + } + } + }; + + template + struct FormatterType + { + static void Format(const std::chrono::nanoseconds& t, FormatterContext& context) { + std::chrono::time_point time(t); + if (!ChronoDetail::WriteTime(time, context)) { + context.BufferOut().BasicWriteType(t.count()); + context.BufferOut().PushBack('n'); + context.BufferOut().PushBack('s'); + } + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatSTDLib.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatSTDLib.h new file mode 100644 index 0000000..dd538f7 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatSTDLib.h @@ -0,0 +1,67 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" + +#include +#include +#include +#include + +namespace ProjectCore::FMT +{ + //------------------------------------------// + //----------------- String -----------------// + //------------------------------------------// + + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::basic_string& t, FormatterContext& context) { + context.BufferOut().FastWriteCharPtr(t.data(), t.size()); + } + }; + + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::basic_string_view& t, FormatterContext& context) { + context.BufferOut().FastWriteCharPtr(t.data(), t.size()); + } + }; + + + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::basic_stringstream& t, FormatterContext& context) { + context.BufferOut().FastWriteCharPtr(t.str(), t.size()); + } + }; + + //------------------------------------------// + //----------------- Memory -----------------// + //------------------------------------------// + + // UniquePtr + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::unique_ptr& t, FormatterContext& context) { + if (context.GetFormatData().TrueValue) FormatterType::Format(t.get(), context); + else FormatterType::Format(*t, context); + } + }; + + // SharedPtr + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::shared_ptr& t, FormatterContext& context) { + if (context.GetFormatData().TrueValue) FormatterType::Format(t.get(), context); + else FormatterType::Format(*t, context); + } + }; + + // WeakPtr + template + struct FormatterType, FormatterContext> { + inline static void Format(const std::weak_ptr& t, FormatterContext& context) { + FormatterType, FormatterContext>::Format(t.lock(), context); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesColor.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesColor.h new file mode 100644 index 0000000..b368765 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesColor.h @@ -0,0 +1,87 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::ResetColor, FormatterContext& context) { + context.GetTextPropertiesParser().ColorModifReset(); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::BasicColorFG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::BasicColorBG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::BasicColor& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::Color24bFG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::Color24bBG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::Color24b& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::ColorCubeFG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::ColorCubeBG& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextColor::ColorCube& t, FormatterContext& context) { + context.GetTextPropertiesParser().AskColorModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesFront.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesFront.h new file mode 100644 index 0000000..a48b1c1 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesFront.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextFront::ResetFront, FormatterContext& context) { + context.GetTextPropertiesParser().FrontModifReset(); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextFront::FrontID t, FormatterContext& context) { + context.GetTextPropertiesParser().AskFrontModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesStyle.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesStyle.h new file mode 100644 index 0000000..eef2d80 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatTextPropertiesStyle.h @@ -0,0 +1,118 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const Detail::TextProperties::ResetProperties, FormatterContext& context) { + context.GetTextPropertiesParser().AllPropertiesReset(); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::ResetStyle, FormatterContext& context) { + context.GetTextPropertiesParser().StyleModifReset(); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Style t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Intensity t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Italic t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Underline t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::Color t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::ColorCube t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::Color24b t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Blink t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Inverted t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Ideogram t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::Script t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::TextProperties::TextStyle::BasicStyle t, FormatterContext& context) { + context.GetTextPropertiesParser().AskStyleModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatterForwarders.h b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatterForwarders.h new file mode 100644 index 0000000..2da7a6a --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BaseFormatter/FormatterForwarders.h @@ -0,0 +1,102 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h" +#include "ProjectCore/FMT/Detail/Forwarders.h" + +namespace ProjectCore::FMT +{ + // Int Forwarders + template + struct FormatterType, FormatterContext> { + static inline void Format(const T t, FormatterContext& context) { + context.BufferOut().WriteIntFormatData(t, context.GetFormatData()); + } + }; + + // UInt Forwarders + template + struct FormatterType, FormatterContext> { + static inline void Format(const T t, FormatterContext& context) { + context.BufferOut().WriteUIntFormatData(t, context.GetFormatData()); + } + }; + + // Float Forwarders + template + struct FormatterType, FormatterContext> { + static void Format(const T t, FormatterContext& context) { + context.BufferOut().WriteFloatFormatData(t, context.GetFormatData()); + } + }; + + // Char Forwarders + template + struct FormatterType, FormatterContext> { + inline static void Format(const T t, FormatterContext& context) { + context.BufferOut().PushBack(t); + } + }; + + // Char Array Forwarders + template + struct FormatterType, FormatterContext> { + static void Format(const T(&t)[SIZE], FormatterContext& context) { + const auto& data = context.GetFormatData(); + + std::size_t begin = (std::size_t)context.GetFormatData().GetSpecifierAsNumber("begin", 0); + std::size_t size = (std::size_t)context.GetFormatData().GetSpecifierAsNumber("size", static_cast((t[SIZE - 1] == 0 ? SIZE - 1 : SIZE) - begin)); + + if (data.HasSpecifier("indent")) + return context.BufferOut().WriteIndentCharPtr(t + begin, static_cast(size)); + + if (data.TrueValue) context.BufferOut().PushBack('\"'); + + // TODO : this check is false becquse it need to check for a custom ShiftType/ShiftSize/ShiftPrint an no a HasSpec + // Cause this check will use the costly one even when it is not needed + if (data.HasSpec == false) + context.BufferOut().FastWriteCharPtr(t + begin, static_cast(size)); + else + context.BufferOut().WriteCharPtr(t + begin, static_cast(size), data.ShiftType, data.ShiftSize, data.ShiftPrint); + + if (data.TrueValue) context.BufferOut().PushBack('\"'); + } + }; + + // Char Pointers Forwarders + template + struct FormatterType, FormatterContext> { + static void Format(const T* t, FormatterContext& context) { + const auto& data = context.GetFormatData(); + + if (t == nullptr) + return context.BufferOut().FastWriteStringView(data.GetSpecifierAsText("null", "[nullptr string]")); + + std::size_t begin = (std::size_t)data.GetSpecifierAsNumber("begin", 0); + std::size_t size = (std::size_t)data.GetSpecifierAsNumber("size", Detail::FORMAT_DATA_NOT_SPECIFIED); + + if (data.HasSpecifier("indent")) + { + if (size == Detail::FORMAT_DATA_NOT_SPECIFIED) + return context.BufferOut().WriteIndentCharPtrNSize(t + begin); + return context.BufferOut().WriteIndentCharPtr(t + begin, size); + } + + if (data.TrueValue) context.BufferOut().PushBack('\"'); + + // TODO : this check is false becquse it need to check for a custom ShiftType/ShiftSize/ShiftPrint an no a HasSpec + // Cause this check will use the costly one even when it is not needed + if (data.HasSpec == false) + { + if (size != Detail::FORMAT_DATA_NOT_SPECIFIED) context.BufferOut().FastWriteCharPtr(t + begin, size); + else context.BufferOut().FastWriteCharPtrNSize(t + begin); + } + else + { + if (size != Detail::FORMAT_DATA_NOT_SPECIFIED) context.BufferOut().WriteCharPtr(t + begin, size, data.ShiftType, data.ShiftSize, data.ShiftPrint); + else context.BufferOut().WriteCharPtrNSize(t + begin, data.ShiftType, data.ShiftSize, data.ShiftPrint); + } + + if (data.TrueValue) context.BufferOut().PushBack('\"'); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h new file mode 100644 index 0000000..eea2756 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContext.h @@ -0,0 +1,174 @@ +#pragma once + +#include "ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h" +#include "ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FMTBufferOut.h" + +#include "FormatterType.h" +#include "Utils/NamedArgs.h" +#include "Utils/IndexArgs.h" +#include "Utils/STDEnumerable.h" + +#include "FormatterTextPropertiesExecutor/IFormatterTextPropertiesExecutor.h" + +#include "FormatterContextArgsTuple.h" + +namespace ProjectCore::FMT::Context +{ + template + class BasicFormatterContext : public BasicContext + { + public: + using Base = BasicContext; + using M_Type = BasicFormatterContext; + + friend Base; + + using typename Base::CharFormatType; + using typename Base::FormatDataType; + using typename Base::StringViewFormat; + using typename Base::FormatBufferType; + using typename Base::ContextArgsInterface; + using typename Base::TextPropertiesParser; + + using StringViewBuffer = std::basic_string_view; + using BufferOutType = Detail::FMTBufferOut; + + public: + BasicFormatterContext(Detail::BasicBufferOutManager& BufferOutManager, Detail::IFormatterTextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties = nullptr); + ~BasicFormatterContext() override; + + protected: + using Base::m_Format; + using Base::m_ValuesIndex; + using Base::m_FormatData; + using Base::m_ContextArgsInterface; + using Base::m_TextPropertiesParser; + + BufferOutType m_BufferOut; + + public: + using Base::Format; + using Base::GetFormatData; + using Base::ForwardFormatData; + using Base::SetFormatData; + using Base::GetContextArgsInterface; + + inline BufferOutType& BufferOut() { return m_BufferOut; } + inline const BufferOutType& BufferOut() const { return m_BufferOut; } + + public: + using Base::Run; + + protected: + void FormatToParamsString(const CharFormat* buffer, std::size_t size) override { m_BufferOut.FastWriteCharPtr(buffer, size); } + void FormatExecParams() override { if (!Parse()) m_BufferOut.PushBack('{'); } + void SetArgsInterfaceCurrentContex() override { m_ContextArgsInterface->SetContext(this); } + + public: + template + void SubContext(const Detail::BufferInProperties& bufferInProperties, NewContextArgs&& ...args); + + template + inline void SubContextArrayFMT(const NewCharFormat (&format)[SIZE], NewContextArgs&& ...args) + { + Detail::BufferInProperties properties(format); + return SubContext(properties, std::forward(args)...); + } + + template + void SubContextPtrFMT(const NewCharFormat* buffer, std::size_t size, NewContextArgs&& ...args) + { + Detail::BufferInProperties properties(buffer, size); + return SubContext(properties, std::forward(args)...); + } + + public: + using Base::GetFormatIndexThrow; + + protected: + using Base::ParseFormatDataBase; + using Base::ParseFormatDataSpecial; + using Base::ParseFormatDataCustom; + using Base::ParseFormatData; + + using Base::ParseSpecial; + using Base::ParseVariable; + using Base::Parse; + + protected: + using Base::ParseTimer; + using Base::ParseDate; + using Base::ParseSetter; + + void ParseTimer() override; + void ParseDate() override; + void ParseSetter() override; + + public: + using Base::FormatReadParameterThrow; + using Base::FormatDataApplyNextOverride; + + public: + // Type formating from FormatterType<> + template + inline void RunType(Type&& type, const Rest&& ...rest) { RunType(type); RunType(std::forward(rest)...); } + template inline void RunType(Type&& type) { FormatterType>::Type, M_Type>::Format(type, *this); } + + template + inline void RunSubType(Type&& type, const Rest&& ...rest) { RunSubType(type); RunSubType(std::forward(rest)...); } + template inline void RunSubType(Type&& type) { + if (m_FormatData.NextOverride.size() == 0) + return RunType(type); + FormatDataType formatDataCopy = m_FormatData; + FormatDataApplyNextOverride(); + RunType(type); + m_FormatData = formatDataCopy; + } + + // Only support basic type that are considered as basic by Buffer class + template + inline void BasicRunType(Type&& type, Rest&& ...rest) { BasicRunType(type); BasicRunType(std::forward(rest)...); } + template inline void BasicRunType(Type&& type) { m_BufferOut.BasicWriteType(type); } + + template + inline void BasicRunSubType(Type&& type, const Rest&& ...rest) { BasicRunSubType(type); BasicRunSubType(std::forward(rest)...); } + template inline void BasicRunSubType(Type&& type) { + if (m_FormatData.NextOverride.size() == 0) + return BasicRunType(type); + FormatDataType formatDataCopy = m_FormatData; + FormatDataApplyNextOverride(); + BasicRunType(type); + m_FormatData = formatDataCopy; + } + + // Type formating from FormatterType<> + template + inline void WriteType(Type&& type, Rest&& ...rest) { RunType(type, std::forward(rest)...); } + template + inline void WriteSubType(Type&& type, Rest&& ...rest) { RunSubType(type, std::forward(rest)...); } + + // Only support basic type that are considered as basic by Buffer class + template + inline void BasicWriteType(Type&& type, Rest&& ...rest) { BasicRunType(type, std::forward(rest)...); } + template + inline void BasicSubWriteType(Type&& type, Rest&& ...rest) { BasicRunSubType(type, std::forward(rest)...); } + + public: + using Base::GetStringViewParamUntil; + using Base::GetStringViewUntil; + using Base::ReadDataType; + + public: + void CheckEndStr(); + }; +} + +#include "BaseFormatter/FormatTextPropertiesColor.h" +#include "BaseFormatter/FormatTextPropertiesStyle.h" +#include "BaseFormatter/FormatTextPropertiesFront.h" +#include "BaseFormatter/BaseFormat.h" +#include "BaseFormatter/FormatSTDLib.h" +#include "BaseFormatter/FormatChrono.h" + +#include "FormatterTextPropertiesExecutor/FormatterNOTextPropertiesExecutor.h" +#include "FormatterTextPropertiesExecutor/FormatterANSITextPropertiesExecutor.h" diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextCoreImpl.h b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextCoreImpl.h new file mode 100644 index 0000000..b227630 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextCoreImpl.h @@ -0,0 +1,46 @@ +#pragma once + +#include "BasicFormatterContext.h" + +namespace ProjectCore::FMT::Context +{ + template + BasicFormatterContext::BasicFormatterContext(Detail::BasicBufferOutManager& BufferOutManager, Detail::IFormatterTextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties) + : Base(textPropertiesExecutor, parentContextProperties) + , m_BufferOut(BufferOutManager) + { + textPropertiesExecutor.SetBuffer(&m_BufferOut); + } + + template + BasicFormatterContext::~BasicFormatterContext() + { + m_BufferOut.EndContext(); + m_BufferOut.PushBackEndChar(); + } + + template + template + void BasicFormatterContext::SubContext(const Detail::BufferInProperties& bufferInProperties, Args&& ...args) + { + using ContextType = BasicFormatterContext; + auto childContextArgsInterface = Detail::FormatterContextArgsTupleInterface(std::forward(args)...); + Detail::FMTFormatBuffer format(bufferInProperties); + + // TODO : Disable because cause TextProperties to not be restore correctly + if constexpr (false && std::is_same_v) + { + Run(format, &childContextArgsInterface); + } + else + { + Detail::IFormatterTextPropertiesExecutor& am_TextPropertiesExecutor = reinterpret_cast&>(m_TextPropertiesParser.GetTextPropertiesExecutor()); + + ContextType child(m_BufferOut.GetBufferOutManager(), am_TextPropertiesExecutor, &m_TextPropertiesParser.GetCurrentContextProperties()); + child.BufferOut().ReloadBuffer(m_BufferOut); + child.Run(format, &childContextArgsInterface); + m_BufferOut.ReloadBuffer(child.BufferOut()); + am_TextPropertiesExecutor.SetBuffer(&m_BufferOut); + } + } +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextParseImpl.h b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextParseImpl.h new file mode 100644 index 0000000..e45bc5e --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/BasicFormatterContextParseImpl.h @@ -0,0 +1,45 @@ +#pragma once + +#include "BasicFormatterContext.h" +#include "BasicFormatterContextCoreImpl.h" + +namespace ProjectCore::FMT::Context +{ + /////---------- AAHHHHHHHHH ----------///// + template + void BasicFormatterContext::ParseTimer() + { + ParseFormatData(); + std::chrono::nanoseconds ns = std::chrono::high_resolution_clock::now() - Detail::FormatterHandler::GetTimeShift(); + m_FormatData.AddSpecifier("pattern", "%h:%m:%s.%ms", true); + WriteType(ns); + } + + template + void BasicFormatterContext::ParseDate() + { + ParseFormatData(); + std::chrono::nanoseconds ns = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + Detail::FormatterHandler::GetHoursShift(); + m_FormatData.AddSpecifier("pattern", "%h:%m:%s.%ms", true); + WriteType(ns); + } + + template + void BasicFormatterContext::ParseSetter() + { + ParseFormatData(); + + // Indent + auto indent = m_FormatData.GetSpecifier("indent"); + if (indent != nullptr) + { + if (indent->ValueHasNumber == true) + BufferOut().SetIndent(static_cast(indent->ValueAsNumber)); + else + BufferOut().SetIndent(); + } + } + +} + + diff --git a/src/ProjectCore/FMT/Context/FormatterContext/FormatterContextArgsTuple.h b/src/ProjectCore/FMT/Context/FormatterContext/FormatterContextArgsTuple.h new file mode 100644 index 0000000..50a8150 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/FormatterContextArgsTuple.h @@ -0,0 +1,183 @@ + +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h" + +#include "FormatterType.h" + +namespace ProjectCore::FMT::Detail +{ + template + struct FormatterContextArgsTuple; + + template <> + struct FormatterContextArgsTuple<> + { + + public: + FormatterContextArgsTuple() = default; + + public: + static inline constexpr std::size_t Size() { return 0; } + + public: + template + inline void RunTypeAtIndex(FormatterContext&, Detail::FormatIndex) + { throw Detail::FMTBufferWrongIndex(); } + + template + inline Detail::FormatIndex GetIndexOfCurrentNameArg(FormatterContext&, Detail::FormatIndex) + { return Detail::FormatIndex(); } + + inline std::any GetTypeAtIndex(Detail::FormatIndex) + { return {}; } + + template + inline void GetTypeAtIndexCast(T*, Detail::FormatIndex) + { } + + template + inline void GetTypeAtIndexConvert(T*, Detail::FormatIndex) + { } + }; + + template + struct FormatterContextArgsTuple : public FormatterContextArgsTuple + { + private: + using TypeWithoutRef = std::remove_reference_t; + + public: + FormatterContextArgsTuple(const TypeWithoutRef& t, Rest&&... rest) + : FormatterContextArgsTuple(std::forward(rest)...), m_Value(t) + {} + + private: + const TypeWithoutRef &m_Value; + + public: + static inline constexpr std::size_t Size() { return sizeof...(Rest) + 1; } + + public: + template + inline void RunTypeAtIndex(FormatterContext &context, Detail::FormatIndex idx) { + if (idx.Is0()) + return context.RunType(m_Value); + return FormatterContextArgsTuple::RunTypeAtIndex(context, idx.GetPrev()); + } + + public: + template + inline Detail::FormatIndex GetIndexOfCurrentNameArg(FormatterContext& context, Detail::FormatIndex beginSearchIndex) { + if constexpr (Detail::IsANamedArgs>::value) + { + if (context.Format().NextIsANamedArgs(m_Value.GetName())) + return beginSearchIndex; + } + return FormatterContextArgsTuple::GetIndexOfCurrentNameArg(context, beginSearchIndex.GetNext()); + } + + public: + inline std::any GetTypeAtIndex(Detail::FormatIndex idx) + { + if (idx.Is0()) + return std::any{&m_Value}; + return FormatterContextArgsTuple::GetTypeAtIndex(idx.GetPrev()); + } + + public: + template + inline void GetTypeAtIndexCast(T* value, Detail::FormatIndex idx) + { + if (idx.Is0()) + { + if constexpr ( FMTIsContextSame ) + { + return *value = m_Value; + } + else + { + // Warrning : Need to transmit : 'Could not convert' + return; + } + } + return FormatterContextArgsTuple::template GetTypeAtIndexCast(value, idx.GetPrev()); + } + + template + inline void GetTypeAtIndexConvert(T* value, Detail::FormatIndex idx) + { + if (idx.Is0()) + { + if constexpr ( FMTCanContextConvert ) + { + *value = FMTContextConvert::Convert(m_Value); + return; + } + else + { + // Warrning : Need to transmit : 'Could not convert' + return; + } + } + return FormatterContextArgsTuple::template GetTypeAtIndexConvert(value, idx.GetPrev()); + } + }; + + template + class FormatterContextArgsTupleInterface : public BasicContextArgsTupleInterface + { + public: + using Base = BasicContextArgsTupleInterface; + using ContextArgsType = FormatterContextArgsTuple; + + using Base::m_Context; + + public: + FormatterContextArgsTupleInterface(Args&&... args) + : Base() + , m_contextArgs(std::forward(args)...) + {} + ~FormatterContextArgsTupleInterface() override = default; + + public: + size_t Size() override + { return m_contextArgs.Size(); } + + void RunTypeAtIndex(Detail::FormatIndex idx) override + { return m_contextArgs.RunTypeAtIndex(*m_Context, idx); } + + Detail::FormatIndex GetIndexOfCurrentNameArg() override + { return m_contextArgs.GetIndexOfCurrentNameArg(*m_Context, Detail::FormatIndex{0}); } + + std::any GetTypeAtIndexImpl(Detail::FormatIndex idx) override + { return m_contextArgs.GetTypeAtIndex(idx); } + + void RunFuncAtImpl(Detail::FormatIndex idx, std::function func) override + { + return func(m_contextArgs.GetTypeAtIndex(idx)); + } + + public: + template + T GetTAtConvert(Detail::FormatIndex idx) + { + T res; + m_contextArgs.template GetTypeAtIndexConvert(&res, idx); + return res; + } + + Detail::FormatIndex GetFormatIndexAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + typename Context::StringViewFormat GetStringAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + std::int64_t GetIntAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + protected: + ContextArgsType m_contextArgs; + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterANSITextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterANSITextPropertiesExecutor.h new file mode 100644 index 0000000..5b2fd6d --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterANSITextPropertiesExecutor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "IFormatterTextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class FormatterANSITextPropertiesExecutor : public IFormatterTextPropertiesExecutor + { + public: + ~FormatterANSITextPropertiesExecutor() override = default; + + public: + using Base = IFormatterTextPropertiesExecutor; + using Base::SetBuffer; + + protected: + using Base::m_Buffer; + + public: + void AllPropertiesReset() override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', 0, 'm'); } + + public: + void ResetColor() override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', 39, ';', 49, 'm'); } + void ExecuteColor(const TextProperties::TextColor::BasicColorFG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteColor(const TextProperties::TextColor::BasicColorBG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteColor(const TextProperties::TextColor::BasicColor& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t.Fg) , ';', static_cast(t.Bg), 'm'); } + void ExecuteColor(const TextProperties::TextColor::Color24bFG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[38;2;", t.R, ';', t.G, ';', t.B, 'm'); } + void ExecuteColor(const TextProperties::TextColor::Color24bBG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[48;2;", t.R, ';', t.G, ';', t.B, 'm'); } + void ExecuteColor(const TextProperties::TextColor::Color24b& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[38;2;", t.Fg.R, ';', t.Fg.G, ';', t.Fg.B, "; 48; 2;", t.Bg.R, ';', t.Bg.G, ';', t.Bg.B, 'm'); } + void ExecuteColor(const TextProperties::TextColor::ColorCubeFG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[38;5;", t.GetColorRef(), 'm'); } + void ExecuteColor(const TextProperties::TextColor::ColorCubeBG& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[48;5;", t.GetColorRef(), 'm'); } + void ExecuteColor(const TextProperties::TextColor::ColorCube& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[48;5;", t.Fg.GetColorRef(), ";48;5;", t.Bg.GetColorRef(), 'm'); } + + public: + void ResetFront() override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', TextProperties::TextFront::FrontID::DefaultFrontID, 'm'); } + void ExecuteFront(const TextProperties::TextFront::FrontID& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', t.ID, 'm'); } + + public: + void ResetStyle() override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', 0, 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Intensity& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Italic& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Underline& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color&) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[59m"); } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::ColorCube& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[58;5;", t.GetColorRef(), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color24b& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType("\033[58;2;", t.R, ';', t.G, ';', t.B, 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Blink& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Inverted& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Ideogram& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + void ExecuteStyle(const TextProperties::TextStyle::Script& t) override { NoStrideFunction noStride(*m_Buffer); m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm'); } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterNOTextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterNOTextPropertiesExecutor.h new file mode 100644 index 0000000..037e28d --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/FormatterNOTextPropertiesExecutor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "IFormatterTextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class FormatterNOTextPropertiesExecutor : public IFormatterTextPropertiesExecutor + { + public: + ~FormatterNOTextPropertiesExecutor() override = default; + + public: + using Base = IFormatterTextPropertiesExecutor; + using Base::SetBuffer; + + protected: + using Base::m_Buffer; + + public: + void AllPropertiesReset() override {} + + public: + void ResetColor() override {} + void ExecuteColor(const TextProperties::TextColor::BasicColorFG&) override {} + void ExecuteColor(const TextProperties::TextColor::BasicColorBG&) override {} + void ExecuteColor(const TextProperties::TextColor::BasicColor&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24bFG&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24bBG&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24b&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCubeFG&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCubeBG&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCube&) override {} + + public: + void ResetFront() override {} + void ExecuteFront(const TextProperties::TextFront::FrontID&) override {} + + public: + void ResetStyle() override {} + void ExecuteStyle(const TextProperties::TextStyle::Intensity&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Italic&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Underline&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::ColorCube&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color24b&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Blink&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Inverted&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Ideogram&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Script&) override {} + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/IFormatterTextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/IFormatterTextPropertiesExecutor.h new file mode 100644 index 0000000..1206882 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/FormatterTextPropertiesExecutor/IFormatterTextPropertiesExecutor.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class IFormatterTextPropertiesExecutor : public ITextPropertiesExecutor + { + public: + ~IFormatterTextPropertiesExecutor() override = default; + + public: + void SetBuffer(BufferOutType* buffer) { m_Buffer = buffer; } + + protected: + BufferOutType* m_Buffer{ nullptr }; + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/FormatterType.h b/src/ProjectCore/FMT/Context/FormatterContext/FormatterType.h new file mode 100644 index 0000000..dcbc82f --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/FormatterType.h @@ -0,0 +1,50 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/Tools/MapMacro.h" + +#define PROJECTCORE_FORMATTER_DECLARED +namespace ProjectCore::FMT +{ + template> + struct FormatterType + { + static inline void Format(const T&, FormatterContext& context) { +#ifdef UNKOWN_TYPE_MESSAGE + context.SubContextArrayFMT("({C:red}FMT unknow type: {})", typeid(T).name()); +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::FMTShouldNotEndHere{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + throw Detail::FMTShouldNotEndHere{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + } + }; +} + +#define PROJECTCORE_INTERNAL_ADDVALUE(x) value.x +#define PROJECTCORE_AUTO_FORMATTER_X(Type, fmt, ...) template\ + struct ProjectCore::FMT::FormatterType {\ + static void Format(const Type& value, FormatterContext& context) {\ + context.SubContextArrayFMT(fmt, FOR_EACH(PROJECTCORE_INTERNAL_ADDVALUE, __VA_ARGS__));\ + }\ + }; + +#define PROJECTCORE_AUTO_FORMATTER(Type, fmt, ...) template\ + struct ProjectCore::FMT::FormatterType {\ + static void Format(const Type& value, FormatterContext& context) {\ + context.SubContextArrayFMT(fmt, __VA_ARGS__);\ + }\ + }; + +#define PROJECTCORE_AUTO_FORMATTER_T(Type, fmt, ...) template\ + struct ProjectCore::FMT::FormatterType {\ + static void Format(const Type&, FormatterContext& context) {\ + context.SubContextArrayFMT(fmt, __VA_ARGS__);\ + }\ + }; + diff --git a/src/ProjectCore/FMT/Context/FormatterContext/UtilityFunctions.h b/src/ProjectCore/FMT/Context/FormatterContext/UtilityFunctions.h new file mode 100644 index 0000000..111a69f --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/UtilityFunctions.h @@ -0,0 +1,223 @@ +#pragma once + +#include "BasicFormatterContext.h" +#include "BasicFormatterContextCoreImpl.h" +#include "BasicFormatterContextParseImpl.h" + +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h" + +#include + +namespace ProjectCore::FMT +{ + /////---------- Impl with as Format ----------////// + namespace Detail + { + template + requires (IsCharType::Value && IsCharType::Value) + void FormatInBufferOutManager(Detail::BasicBufferOutManager& bufferOutManager, const Detail::BufferInProperties& bufferInProperties, bool newline, Args&& ...args) + { + using ContextType = Context::BasicFormatterContext; + Detail::FormatterANSITextPropertiesExecutor textPropertiesExecutor; + ContextType context(bufferOutManager, textPropertiesExecutor); + + auto contextArgsInterface = Detail::FormatterContextArgsTupleInterface(std::forward(args)...); + Detail::FMTFormatBuffer format(bufferInProperties); + context.Run(format, &contextArgsInterface); + if (newline) + context.BufferOut().PushBack('\n'); + context.Terminate(); + } + + template + void FormatInBufferOutManager(Detail::BasicBufferOutManager& bufferOutManager, bool newline, T&& t) + { + using ContextType = Context::BasicFormatterContext; + Detail::FormatterANSITextPropertiesExecutor textPropertiesExecutor; + ContextType context(bufferOutManager, textPropertiesExecutor); + context.WriteType(t); + if (newline) + context.BufferOut().PushBack('\n'); + context.Terminate(); + } + + template + requires (IsCharType::Value && IsCharType::Value) + std::shared_ptr> FormatAndGetBufferOut(Detail::BufferInProperties& bufferInProperties, Args&& ...args) + { + std::shared_ptr> bufferOutManager = std::make_shared>(128); + FormatInBufferOutManager(*bufferOutManager, bufferInProperties, false, std::forward(args)...); + return bufferOutManager; + } + + template + std::shared_ptr> FormatAndGetBufferOut(T&& t) + { + std::shared_ptr> bufferOutManager = std::make_shared>(128); + FormatInBufferOutManager(*bufferOutManager, false, std::forward(t)); + return bufferOutManager; + } + } + + + template + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void FormatInChar(CharBuffer(&buffer)[BUFFER_SIZE], const Format& format, Args&& ...args) { + Detail::GivenBufferOutManager bufferOutManager(buffer); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + } + + + template + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void FormatInChar(CharBuffer const buffer, const std::size_t bufferSize, const Format& format, Args&& ...args) { + Detail::GivenBufferOutManager bufferOutManager(buffer, bufferSize); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + } + + + template::Type, typename ...Args> + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void CFilePrint(FILE* stream, const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + + std::fwrite(bufferOutManager.GetBuffer(), bufferOutManager.GetLastGeneratedDataSize(), 1, stream); + std::fflush(stream); + } + + template::Type, typename ...Args> + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void CFilePrintLn(FILE* stream, const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, true, std::forward(args)...); + + std::fwrite(bufferOutManager.GetBuffer(), bufferOutManager.GetLastGeneratedDataSize(), 1, stream); + std::fflush(stream); + } + + + template::Type, typename ...Args> + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void FilePrint(std::basic_ostream& stream, const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(std::forward(format)); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + + stream.write(bufferOutManager.GetBuffer(), bufferOutManager.GetLastGeneratedDataSize()); + stream.flush(); + } + + template::Type, typename ...Args> + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void FilePrintLn(std::basic_ostream& stream, const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, true, std::forward(args)...); + + stream.write(bufferOutManager.GetBuffer(), bufferOutManager.GetLastGeneratedDataSize()); + stream.flush(); + } + + + template + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + void FormatInString(std::basic_string& str, const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + str = bufferOutManager.GetLastGeneratedString(); + } + + + template::Type, typename ...Args> + requires (Detail::CanBeUseForFMTBufferIn && Detail::IsCharType::Value) + inline std::basic_string FormatString(const Format& format, Args&& ...args) { + Detail::DynamicBufferOutManager bufferOutManager(256); + Detail::BufferInProperties bufferInProperties(format); + Detail::FormatInBufferOutManager(bufferOutManager, bufferInProperties, false, std::forward(args)...); + return bufferOutManager.GetLastGeneratedString(); + } + + + /////---------- NO-FORMAT Impl except for string which are formatted for avoid {} ----------////// + + template + requires (Detail::IsCharType::Value) + void FormatInChar(CharBuffer(&buffer)[BUFFER_SIZE], T&& t) { + Detail::GivenBufferOutManager bufferOutManager(buffer, BUFFER_SIZE); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + } + + template + requires (Detail::IsCharType::Value) + void FormatInChar(CharBuffer* const buffer, const std::size_t bufferSize, T&& t) { + Detail::GivenBufferOutManager bufferOutManager(buffer, bufferSize); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + } + + + template + requires (Detail::IsCharType::Value) + void CFilePrint(FILE* stream, T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + + std::fwrite(bufferOutManager.GetBuffer(), static_cast(bufferOutManager.GetLastGeneratedDataSize()), 1, stream); + std::fflush(stream); + } + + template + requires (Detail::IsCharType::Value) + void CFilePrintLn(FILE* stream, T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, true, std::forward(t)); + + std::fwrite(bufferOutManager.GetBuffer(), static_cast(bufferOutManager.GetLastGeneratedDataSize()), 1, stream); + std::fflush(stream); + } + + + template + requires (Detail::IsCharType::Value) + void FilePrint(std::basic_ostream& stream, T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + + stream.write(bufferOutManager.GetBuffer(), static_cast(bufferOutManager.GetLastGeneratedDataSize())); + stream.flush(); + } + + template + requires (Detail::IsCharType::Value) + void FilePrintLn(std::basic_ostream& stream, T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, true, std::forward(t)); + + stream.write(bufferOutManager.GetBuffer(), static_cast(bufferOutManager.GetLastGeneratedDataSize())); + stream.flush(); + } + + + template + requires (Detail::IsCharType::Value) + void FormatInString(std::basic_string& str, T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + str = bufferOutManager.GetLastGeneratedString(); + } + + template + requires (Detail::IsCharType::Value) + inline std::basic_string FormatString(T&& t) { + Detail::DynamicBufferOutManager bufferOutManager(32); + Detail::FormatInBufferOutManager(bufferOutManager, false, std::forward(t)); + return bufferOutManager.GetLastGeneratedString(); + } +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/Utils/IndexArgs.h b/src/ProjectCore/FMT/Context/FormatterContext/Utils/IndexArgs.h new file mode 100644 index 0000000..8878df4 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/Utils/IndexArgs.h @@ -0,0 +1,32 @@ +#pragma once + +#include "../FormatterType.h" + +namespace ProjectCore::FMT +{ + template + struct FCIndexArgs { + + FCIndexArgs(const std::uint8_t idx, const T& t) + : m_Value(t), m_Idx(idx) {} + + public: + inline bool IsRightIdx(std::uint8_t idx) const { return idx == m_Idx; } + + public: + inline const T& GetValue() const { return m_Value; } + + protected: + const T& m_Value; + const std::uint8_t m_Idx; + }; + + template + struct FormatterType, FormatterContext> + { + template + inline static void Format(const FCIndexArgs& t, FormatterContext& context) { + context.RunType(t.GetValue()); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/FormatterContext/Utils/NamedArgs.h b/src/ProjectCore/FMT/Context/FormatterContext/Utils/NamedArgs.h new file mode 100644 index 0000000..f7b8771 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/Utils/NamedArgs.h @@ -0,0 +1,97 @@ +#pragma once + +#include "../FormatterType.h" + +namespace ProjectCore::FMT +{ + /////---------- string_view NamedArgs Do not allocate memory (Best) ----------///// + template + struct StringViewNamedArgs + { + template + StringViewNamedArgs(const CharName(&name)[SIZE], const T& t) + : m_Name(name), value(t) {} + + StringViewNamedArgs(const std::basic_string_view& name, const T& t) + : m_Name(name), value(t) {} + + public: + T& GetValue() { return value; } + const T& GetValue() const { return value; } + std::basic_string_view GetName() const { return m_Name; } + + protected: + std::basic_string_view m_Name; + const T& value; + }; + + template + struct FormatterType, FormatterContext> + { + inline static void Format(const StringViewNamedArgs& t, FormatterContext& context) { + context.RunType(t.GetValue()); + } + }; + + + /////---------- stringNamedArgs Allocate memory (Only if necessary) ----------///// + template + struct StringNamedArgs + { + StringNamedArgs(const std::string& str, const T& t) + : m_Name(str), value(t) {} + + StringNamedArgs(std::string&& str, const T& t) + : m_Name(std::move(str)), value(t) {} + + public: + T& GetValue() { return value; } + const T& GetValue() const { return value; } + std::basic_string_view GetName() const { return m_Name; } + + protected: + std::basic_string m_Name; + const T& value; + }; + + template + struct FormatterType, FormatterContext> + { + inline static void Format(const StringNamedArgs& t, FormatterContext& context) { + context.RunType(t.GetValue()); + } + }; + + + namespace Detail { + template + struct IsANamedArgs { + public: + [[maybe_unused]] inline constexpr static bool value = false; + }; + + template + struct IsANamedArgs> { + [[maybe_unused]] inline constexpr static bool value = true; + }; + + template + struct IsANamedArgs> { + [[maybe_unused]] inline constexpr static bool value = true; + }; + + template + inline constexpr bool IsANamedArgsValue = false; + + template + inline constexpr bool IsANamedArgsValue> = true; + + template + inline constexpr bool IsANamedArgsValue> = true; + } +} + + +#define FORMAT(value) ProjectCore::FMT::StringViewNamedArgs(#value, value) +#define FORMAT_SV(name, value) ProjectCore::FMT::StringViewNamedArgs(name, value) +#define FORMAT_STR(name, value) ProjectCore::FMT::StringNamedArgs(name, value) diff --git a/src/ProjectCore/FMT/Context/FormatterContext/Utils/STDEnumerable.h b/src/ProjectCore/FMT/Context/FormatterContext/Utils/STDEnumerable.h new file mode 100644 index 0000000..b38e1f7 --- /dev/null +++ b/src/ProjectCore/FMT/Context/FormatterContext/Utils/STDEnumerable.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +#include "../FormatterType.h" +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT +{ + class STDEnumerableUtility + { + public: + static constexpr std::string_view DefaultJoin = ", "; + static constexpr std::string_view DefaultBegin = "{ "; + static constexpr std::string_view DefaultEnd = " }"; + }; + + template + class STDEnumerable + { + public: + explicit inline STDEnumerable(const T& value, + const std::basic_string_view& strJoin = ", ", + const std::basic_string_view& strBegin = "{ ", + const std::basic_string_view& strEnd = " }", + const Detail::DataType beginIdx = 0, + const Detail::DataType size = Detail::FORMAT_DATA_NOT_SPECIFIED) + : m_Value(value) + , m_StrJoin(strJoin) + , m_StrBegin(strBegin) + , m_StrEnd(strEnd) + , m_BeginIdx(beginIdx) + , m_Size(size == Detail::FORMAT_DATA_NOT_SPECIFIED ? (Detail::DataType)value.size() - beginIdx : size) + { + } + + inline const T& GetValue() const { return m_Value; } + + inline std::basic_string_view GetStrJoin() const { return m_StrJoin; } + inline std::basic_string_view GetStrBegin() const { return m_StrBegin; } + inline std::basic_string_view GetStrEnd() const { return m_StrEnd; } + + inline Detail::DataType GetBeginIdx() const { return m_BeginIdx; } + inline Detail::DataType GetSize() const { return m_Size; } + + private: + const T& m_Value; + + std::basic_string_view m_StrJoin; + std::basic_string_view m_StrBegin; + std::basic_string_view m_StrEnd; + + Detail::DataType m_BeginIdx; + Detail::DataType m_Size; + }; + + template + struct FormatterType, FormatterContext> { + static void Format(const STDEnumerable& enumerable, FormatterContext& context) { + context.BufferOut().WriteIndentStringView(enumerable.GetStrBegin()); + context.BufferOut().AddIndent(enumerable.GetStrBegin().size()); + + { + Detail::ApplyNextOverrideForThisFunction applNextOverride(context); + + bool first = true; + std::for_each_n(enumerable.GetValue().cbegin() + enumerable.GetBeginIdx(), enumerable.GetSize(), [&](const auto& element) { + if (first) first = false; + else context.BufferOut().WriteIndentStringView(enumerable.GetStrJoin()); + + context.WriteType(element); + }); + } + + context.BufferOut().RemoveIndent(enumerable.GetStrBegin().size()); + context.BufferOut().WriteIndentStringView(enumerable.GetStrEnd()); + } + }; + + + template + struct ForwardAsSTDEnumerable {}; + + template + struct FormatterType, FormatterContext> + { + static void Format(const T& container, FormatterContext& context) { + STDEnumerable enumerable(container, + context.GetFormatData().GetSpecifierAsText("join", STDEnumerableUtility::DefaultJoin), + context.GetFormatData().GetSpecifierAsText("begin", STDEnumerableUtility::DefaultBegin), + context.GetFormatData().GetSpecifierAsText("end", STDEnumerableUtility::DefaultEnd), + context.GetFormatData().GetSpecifierAsNumber("begin", 0), + context.GetFormatData().GetSpecifierAsNumber("size", Detail::FORMAT_DATA_NOT_SPECIFIED)); + + context.WriteType(enumerable); + } + }; + +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/BaseParser.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/BaseParser.h new file mode 100644 index 0000000..2ff28b1 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/BaseParser.h @@ -0,0 +1,307 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" +#include "ParserForwarders.h" + +namespace ProjectCore::FMT +{ + template + struct ParserType { + static inline void Parse(typename ParserContext::DataType&, ParserContext&) { + throw Detail::FMTShouldNotEndHere{}; + } + }; + + template + struct ParserType { + static void Parse(bool& t, ParserContext& context) { + const auto& data = context.GetFormatData(); + + if (!data.TrueValue) { + switch (context.BufferIn().Get()) + { + case 'T': + case 't': + if (context.BufferIn().IsSameForward("True")) + t = true; + + case 'F': + case 'f': + if (context.BufferIn().IsSameForward("False")) + t = false; + + default: + throw Detail::FMTParseError(); + } + return; + } else { + if (context.BufferIn().IsEqualToForward('0')) { t = false; return; } + else if (context.BufferIn().IsEqualToForward('1')) { t = true; return; } + } + + throw Detail::FMTParseError(); + } + }; + + // Int Types +#ifdef FMT_USE_STD_INTEGER + template + struct ParserType { + static inline void Parse(std::int8_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::int16_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::int32_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::int64_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; +#else + template + struct ParserType { + static inline void Parse(signed char& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(short& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(int& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(long& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(long long& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; +#endif + + // UInt Types +#ifdef FMT_USE_STD_INTEGER + template + struct ParserType { + static inline void Parse(std::uint8_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::uint16_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::uint32_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(std::uint64_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; +#else + template + struct ParserType { + static inline void Parse(unsigned char& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(unsigned short& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(unsigned int& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(unsigned long& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(unsigned long long& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; +#endif + + // Float Types + template + struct ParserType { + static inline void Parse(float& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(double& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(long double& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + + + // Char Types + template + struct ParserType { + static inline void Parse(char& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(wchar_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char8_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char16_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char32_t& t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + + template + struct ParserType { + static inline void Parse(char(&t)[SIZE], ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(wchar_t(&t)[SIZE], ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char8_t(&t)[SIZE], ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char16_t(&t)[SIZE], ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char32_t(&t)[SIZE], ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + + template + struct ParserType { + static inline void Parse(char* const t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(wchar_t* const t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char8_t* const t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char16_t* const t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + template + struct ParserType { + static inline void Parse(char32_t* const t, ParserContext& context) { + ParserType, ParserContext>::Parse(t, context); + } + }; + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //------------------ Pointer/Array of Type ------------------// + + template + struct ParserType { + static inline void Parse(void*&, ParserContext&) { + // FIXME + // TODO + } + }; + + template + struct ParserType { + static inline void Parse(T*&, ParserContext&) { + // FIXME + // TODO + } + }; + + template + struct ParserType { + static inline void Parse(T (&)[SIZE], ParserContext&) { + // FIXME + // TODO + } + }; +} + + diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseChrono.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseChrono.h new file mode 100644 index 0000000..11cbbe0 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseChrono.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" +#include + +namespace ProjectCore::FMT::ChronoDetail +{ + +} + +namespace ProjectCore::FMT +{ + +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseSTDLib.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseSTDLib.h new file mode 100644 index 0000000..cf1eaa0 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseSTDLib.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" + +#include +#include +#include + +namespace ProjectCore::FMT +{ + +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesColor.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesColor.h new file mode 100644 index 0000000..e022023 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesColor.h @@ -0,0 +1,87 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" + +namespace ProjectCore::FMT +{ + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::ResetColor, ParserContext& context) { + context.GetTextPropertiesParser().ColorModifReset(); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::BasicColorFG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::BasicColorBG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::BasicColor& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::Color24bFG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::Color24bBG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::Color24b& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::ColorCubeFG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::ColorCubeBG& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextColor::ColorCube& t, ParserContext& context) { + context.GetTextPropertiesParser().ColorModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesFront.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesFront.h new file mode 100644 index 0000000..dce7ab1 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesFront.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" + +namespace ProjectCore::FMT +{ + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextFront::ResetFront, ParserContext& context) { + context.GetTextPropertiesParser().FrontModifReset(); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextFront::FrontID t, ParserContext& context) { + context.GetTextPropertiesParser().FrontModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesStyle.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesStyle.h new file mode 100644 index 0000000..66116ee --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParseTextPropertiesStyle.h @@ -0,0 +1,118 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" + +namespace ProjectCore::FMT +{ + template + struct ParserType + { + static void Format(const Detail::TextProperties::ResetProperties, ParserContext& context) { + context.GetTextPropertiesParser().AllPropertiesReset(); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::ResetStyle, ParserContext& context) { + context.GetTextPropertiesParser().StyleModifReset(); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Style t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Intensity t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Italic t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Underline t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::Color t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::ColorCube t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::UnderlineColor::Color24b t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Blink t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Inverted t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Ideogram t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::Script t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; + + template + struct ParserType + { + static void Format(const Detail::TextProperties::TextStyle::BasicStyle t, ParserContext& context) { + context.GetTextPropertiesParser().StyleModif(t); + } + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParserForwarders.h b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParserForwarders.h new file mode 100644 index 0000000..4cfe618 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BaseParse/ParserForwarders.h @@ -0,0 +1,80 @@ +#pragma once + +#include "ProjectCore/FMT/Context/ParserContext/BasicParserContext.h" +#include "ProjectCore/FMT/Detail/Forwarders.h" + +namespace ProjectCore::FMT +{ + // Int + template + struct ParserType, ParserContext> { + static inline void Parse(T& t, ParserContext& context) { + context.BufferIn().ReadIntFormatData(t, context.GetFormatData()); + } + }; + + // UInt + template + struct ParserType, ParserContext> { + static inline void Parse(T& t, ParserContext& context) { + context.BufferIn().ReadUIntFormatData(t, context.GetFormatData()); + } + }; + + // Float + template + struct ParserType, ParserContext> { + static inline void Parse(T& t, ParserContext& context) { + context.BufferIn().ReadFloatFormatData(t, context.GetFormatData()); + } + }; + + // Char type + template + struct ParserType, ParserContext> { + static inline void Parse(T& t, ParserContext& context) { + context.BufferIn().GetAndForward(t); + } + }; + template + struct ParserType, ParserContext> { + static inline void Parse(T(&t)[SIZE], ParserContext& context) { + const auto& data = context.GetFormatData(); + + std::size_t begin = (std::size_t)context.GetFormatData().GetSpecifierAsNumber("begin", 0); + bool isZeroEnded = context.GetFormatData().HasSpecifier("no-zero-end") == false; + std::size_t size = (std::size_t)context.GetFormatData().GetSpecifierAsNumber("size", static_cast(SIZE - static_cast(isZeroEnded ? 1 : 0) - begin)); + + // if (data.HasSpecifier("indent")) + // return context.BufferIn().ReadIndentCharPtr(t + begin, size); + + if (data.TrueValue) context.BufferIn().Skip('\"'); + + if (context.GetFormatData().HasSpecifier("glob")) + { + auto globberPattern = context.GetFormatData().GetSpecifierAsText("glob"); + context.BufferIn().FastReadCharPtrGlobber(globberPattern, t + begin, size, isZeroEnded); + } + else if (context.GetFormatData().HasSpecifier("regex")) + { + throw Detail::FMTImplError{}; + } + else + { + if (data.HasSpec == false) + context.BufferIn().FastReadCharPtrThrow(t + begin, size, isZeroEnded); + else + context.BufferIn().FastReadCharPtrThrow(t + begin, size, isZeroEnded); + // context.BufferIn().ReadCharPtr(t + begin, size, 0, data.ShiftType, data.ShiftSize, data.ShiftPrint); + } + + if (data.TrueValue) context.BufferIn().Skip('\"'); + } + }; + template + struct ParserType, ParserContext> { + static inline void Parse(T* const, ParserContext&) { + // FIXME + } + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BasicParserContext.h b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContext.h new file mode 100644 index 0000000..eb06c86 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContext.h @@ -0,0 +1,175 @@ +#pragma once + +#include "ProjectCore/FMT/Context/BasicContext/BasicContextInclude.h" +#include "ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h" + +#include "ParserType.h" + +#include "ParserContextArgsTuple.h" + +#include "ParserTextPropertiesExecutor/IParserTextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Context +{ + template + class BasicParserContext : public BasicContext + { + public: + using Base = BasicContext; + using M_Type = BasicParserContext; + + friend Base; + + using typename Base::CharFormatType; + using typename Base::FormatDataType; + using typename Base::StringViewFormat; + using typename Base::FormatBufferType; + using typename Base::ContextArgsInterface; + using typename Base::TextPropertiesParser; + + using StringViewBuffer = std::basic_string_view; + using BufferInType = Detail::FMTBufferIn; + + public: + BasicParserContext(Detail::BufferInProperties bufferProperties, Detail::IParserTextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties = nullptr); + ~BasicParserContext() override = default; + + protected: + using Base::m_Format; + using Base::m_ValuesIndex; + using Base::m_FormatData; + using Base::m_ContextArgsInterface; + using Base::m_TextPropertiesParser; + + BufferInType m_BufferIn; + + public: + using Base::Format; + using Base::GetFormatData; + using Base::ForwardFormatData; + using Base::SetFormatData; + + inline BufferInType& BufferIn() { return m_BufferIn; } + inline const BufferInType& BufferIn() const { return m_BufferIn; } + + public: + using Base::Run; + + protected: + void FormatToParamsString(const CharFormat* buffer, std::size_t size) override { + m_BufferIn.IsSameForwardThrow(buffer, size); + } + + void FormatExecParams() override { + if (Parse() == false) + if (m_BufferIn.IsEqualToForward('{') == false) + throw Detail::FMTParseError(); + } + + void SetArgsInterfaceCurrentContex() override { m_ContextArgsInterface->SetContext(this); } + + public: + template + void SubContext(const Detail::BufferInProperties& bufferInProperties, NewContextArgs&& ...args); + + template + inline void SubContextArrayFMT(const NewCharFormat (&format)[SIZE], NewContextArgs&& ...args) + { + Detail::BufferInProperties properties(format); + return SubContext(properties, std::forward(args)...); + } + + template + void SubContextPtrFMT(const NewCharFormat* buffer, std::size_t size, NewContextArgs&& ...args) + { + Detail::BufferInProperties properties(buffer, size); + return SubContext(properties, std::forward(args)...); + } + + public: + using Base::GetFormatIndexThrow; + + protected: + using Base::ParseFormatDataBase; + using Base::ParseFormatDataSpecial; + using Base::ParseFormatDataCustom; + using Base::ParseFormatData; + + using Base::ParseSpecial; + using Base::ParseVariable; + using Base::Parse; + + protected: + using Base::ParseTimer; + using Base::ParseDate; + using Base::ParseSetter; + + void ParseTimer() override; + void ParseDate() override; + void ParseSetter() override; + + public: + using Base::FormatReadParameterThrow; + using Base::FormatDataApplyNextOverride; + + public: + // Type formating from FormatterType<> + template + inline void RunType(Type& type, Rest&... rest) { RunType(type); RunType(std::forward(rest)...); } + template inline void RunType(Type& type) { ParserType>::Type, M_Type>::Parse(type, *this); } + + template + inline void RunSubType(Type& type, Rest& ...rest) { RunSubType(type); RunSubType(std::forward(rest)...); } + template inline void RunSubType(Type& type) { + if (m_FormatData.NextOverride.size() == 0) + return RunType(type); + FormatDataType formatDataCopy = m_FormatData; + FormatDataApplyNextOverride(); + RunType(type); + m_FormatData = formatDataCopy; + } + + // Only support basic type that are considered as basic by Buffer class + template + inline void BasicRunType(Type& type, Rest&... rest) { BasicRunType(type); BasicRunType(std::forward(rest)...); } + template inline void BasicRunType(Type& type) { m_BufferIn.BasicReadType(type); } + + template + inline void BasicRunSubType(Type& type, Rest&... rest) { BasicRunSubType(type); BasicRunSubType(std::forward(rest)...); } + template inline void BasicRunSubType(Type& type) { + if (m_FormatData.NextOverride.size() == 0) + return BasicRunType(type); + FormatDataType formatDataCopy = m_FormatData; + FormatDataApplyNextOverride(); + BasicRunType(type); + m_FormatData = formatDataCopy; + } + + // Type formating from ParserType<> + template + inline void ReadType(Type& type, Rest&... rest) { RunType(type, std::forward(rest)...); } + template + inline void ReadSubType(Type& type, Rest&... rest) { RunSubType(type, std::forward(rest)...); } + + // Only support basic type that are considered as basic by Buffer class + template + inline void BasicReadType(Type& type, Rest&... rest) { BasicRunType(type, std::forward(rest)...); } + template + inline void BasicSubReadType(Type& type, Rest&... rest) { BasicRunSubType(type, std::forward(rest)...); } + + public: + using Base::GetStringViewParamUntil; + using Base::GetStringViewUntil; + using Base::ReadDataType; + }; +} + +#include "BaseParse/ParseTextPropertiesColor.h" +#include "BaseParse/ParseTextPropertiesStyle.h" +#include "BaseParse/ParseTextPropertiesFront.h" +#include "BaseParse/BaseParser.h" +#include "BaseParse/ParseSTDLib.h" +#include "BaseParse/ParseChrono.h" + +#include "ParserTextPropertiesExecutor/ParserNOTextPropertiesExecutor.h" +#include "ParserTextPropertiesExecutor/ParserANSITextPropertiesExecutor.h" diff --git a/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextCoreImpl.h b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextCoreImpl.h new file mode 100644 index 0000000..1e1bfee --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextCoreImpl.h @@ -0,0 +1,41 @@ +#pragma once + +#include "BasicParserContext.h" + +namespace ProjectCore::FMT::Context +{ + template + BasicParserContext::BasicParserContext(Detail::BufferInProperties bufferProperties, Detail::IParserTextPropertiesExecutor& textPropertiesExecutor, const Detail::TextProperties::Properties* parentContextProperties) + : Base(textPropertiesExecutor, parentContextProperties) + , m_BufferIn(bufferProperties) + { + // TODO + // textPropertiesExecutor.SetBuffer(m_BufferIn); + } + + template + template + void BasicParserContext::SubContext(const Detail::BufferInProperties& bufferInProperties, Args&& ...args) { + using ContextType = BasicParserContext; + auto childContextArgsInterface = Detail::ParserContextArgsTupleInterface(std::forward(args)...); + Detail::FMTFormatBuffer format(bufferInProperties); + + // TODO : Disable because cause TextProperties to not be restore correctly + if constexpr (false && std::is_same_v) + { + Run(format, &childContextArgsInterface); + } + else + { + Detail::IParserTextPropertiesExecutor& cm_TextPropertiesExecutor = reinterpret_cast&>(m_TextPropertiesParser.GetTextPropertiesExecutor()); + + Detail::BufferInProperties properties(m_BufferIn.GetBuffer(), m_BufferIn.GetBufferSize()); + ContextType child(properties, cm_TextPropertiesExecutor, &m_TextPropertiesParser.GetCurrentContextProperties()); + child.BufferIn().ReloadBuffer(m_BufferIn); + child.Run(format, &childContextArgsInterface); + m_BufferIn.ReloadBuffer(child.BufferIn()); + + cm_TextPropertiesExecutor.SetBuffer(&m_BufferIn); + } + } +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextParseImpl.h b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextParseImpl.h new file mode 100644 index 0000000..cff168b --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/BasicParserContextParseImpl.h @@ -0,0 +1,24 @@ +#pragma once + +#include "BasicParserContext.h" +#include "BasicParserContextCoreImpl.h" + +namespace ProjectCore::FMT::Context +{ + /////---------- AAHHHHHHHHH ----------///// + template + void BasicParserContext::ParseTimer() { + std::chrono::nanoseconds ns = std::chrono::high_resolution_clock::now() - Detail::FormatterHandler::GetTimeShift(); + RunType(ns); + } + + template + void BasicParserContext::ParseDate() { + std::chrono::nanoseconds ns = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + Detail::FormatterHandler::GetHoursShift(); + RunType(ns); + } + + template + void BasicParserContext::ParseSetter() { + } +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/ParserContextArgsTuple.h b/src/ProjectCore/FMT/Context/ParserContext/ParserContextArgsTuple.h new file mode 100644 index 0000000..ea41dfb --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/ParserContextArgsTuple.h @@ -0,0 +1,180 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/FMT/Context/BasicContext/Utils/BasicContextArgsTupleInterface.h" + +#include "ParserType.h" + +namespace ProjectCore::FMT::Detail +{ + template + struct ParserContextArgsTuple; + + template <> + struct ParserContextArgsTuple<> + { + public: + ParserContextArgsTuple() = default; + + public: + static inline constexpr std::size_t Size() { return 0; } + + public: + template + inline void RunTypeAtIndex(FormatterContext&, Detail::FormatIndex) + { throw Detail::FMTBufferWrongIndex(); } + + template + inline Detail::FormatIndex GetIndexOfCurrentNameArg(FormatterContext&, Detail::FormatIndex) + { return Detail::FormatIndex(); } + + inline std::any GetTypeAtIndex(Detail::FormatIndex) + { return {}; } + + template + inline void GetTypeAtIndexCast(T*, Detail::FormatIndex) + { } + + template + inline void GetTypeAtIndexConvert(T*, Detail::FormatIndex) + { } + }; + + template + struct ParserContextArgsTuple : ParserContextArgsTuple + { + private: + using TypeWithoutRef = std::remove_reference_t; + + public: + ParserContextArgsTuple(TypeWithoutRef& t, Rest&... rest) : ParserContextArgsTuple(std::forward(rest)...), m_Value(t) {} + + private: + TypeWithoutRef& m_Value; + + public: + static inline constexpr std::size_t Size() { return sizeof...(Rest) + 1; } + + public: + template + inline void RunTypeAtIndex(FormatterContext &context, Detail::FormatIndex idx) { + if (idx.Is0()) + return context.RunType(m_Value); + return ParserContextArgsTuple::RunTypeAtIndex(context, idx.GetPrev()); + } + + public: + template + inline Detail::FormatIndex GetIndexOfCurrentNameArg(FormatterContext& context, Detail::FormatIndex beginSearchIndex) { + if constexpr (Detail::IsANamedArgs>::value) + { + if (context.Format().NextIsANamedArgs(m_Value.GetName())) + return beginSearchIndex; + } + return ParserContextArgsTuple::GetIndexOfCurrentNameArg(context, beginSearchIndex.GetNext()); + } + + public: + inline std::any GetTypeAtIndex(Detail::FormatIndex idx) + { + if (idx.Is0()) + return std::any{&m_Value}; + return ParserContextArgsTuple::GetTypeAtIndex(idx.GetPrev()); + } + + public: + template + inline void GetTypeAtIndexCast(T* value, Detail::FormatIndex idx) + { + if (idx.Is0()) + { + if constexpr (FMTIsContextSame) + { + return *value = m_Value; + } + else + { + // Warrning : Need to transmit : 'Could not convert' + return; + } + } + return ParserContextArgsTuple::template GetTypeAtIndexCast(value, idx.GetPrev()); + } + + template + inline void GetTypeAtIndexConvert(T* value, Detail::FormatIndex idx) + { + if (idx.Is0()) + { + if constexpr (FMTCanContextConvert) + { + *value = FMTContextConvert::Convert(m_Value); + return; + } + else + { + // Warrning : Need to transmit : 'Could not convert' + return; + } + } + return ParserContextArgsTuple::template GetTypeAtIndexConvert(value, idx.GetPrev()); + } + }; + + + template + class ParserContextArgsTupleInterface : public BasicContextArgsTupleInterface + { + public: + using Base = BasicContextArgsTupleInterface; + using ContextArgsType = ParserContextArgsTuple; + + using Base::m_Context; + + public: + ParserContextArgsTupleInterface(Args&&... args) + : Base() + , m_contextArgs(std::forward(args)...) + {} + ~ParserContextArgsTupleInterface() override = default; + + public: + std::size_t Size() override + { return m_contextArgs.Size(); } + + void RunTypeAtIndex(Detail::FormatIndex idx) override + { return m_contextArgs.RunTypeAtIndex(*m_Context, idx); } + + Detail::FormatIndex GetIndexOfCurrentNameArg() override + { return m_contextArgs.GetIndexOfCurrentNameArg(*m_Context, Detail::FormatIndex{0}); } + + std::any GetTypeAtIndexImpl(Detail::FormatIndex idx) override + { return m_contextArgs.GetTypeAtIndex(idx); } + + void RunFuncAtImpl(Detail::FormatIndex idx, std::function func) override + { + return func(m_contextArgs.GetTypeAtIndex(idx)); + } + + public: + template + T GetTAtConvert(Detail::FormatIndex idx) + { + T res; + m_contextArgs.template GetTypeAtIndexConvert(&res, idx); + return res; + } + + Detail::FormatIndex GetFormatIndexAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + typename Context::StringViewFormat GetStringAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + int64_t GetIntAt(Detail::FormatIndex idx) override + { return GetTAtConvert(idx); } + + protected: + ContextArgsType m_contextArgs; + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/IParserTextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/IParserTextPropertiesExecutor.h new file mode 100644 index 0000000..085b53c --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/IParserTextPropertiesExecutor.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" +#include "ProjectCore/FMT/Context/BasicContext/ITextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class IParserTextPropertiesExecutor : public ITextPropertiesExecutor + { + public: + ~IParserTextPropertiesExecutor() override = default; + + public: + void SetBuffer(BufferInType* buffer) { m_Buffer = buffer; } + + protected: + BufferInType* m_Buffer; + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserANSITextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserANSITextPropertiesExecutor.h new file mode 100644 index 0000000..19106a4 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserANSITextPropertiesExecutor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "IParserTextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class ParserANSITextPropertiesExecutor : public IParserTextPropertiesExecutor + { + public: + ~ParserANSITextPropertiesExecutor() override = default; + + public: + using Base = IParserTextPropertiesExecutor; + using Base::SetBuffer; + + protected: + using Base::m_Buffer; + + public: + void AllPropertiesReset() override { /*m_Buffer->BasicWriteType('\033', '[', 0, 'm');*/ } + + public: + void ResetColor() override { /*m_Buffer->BasicWriteType('\033', '[', 39, ';', 49, 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::BasicColorFG&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::BasicColorBG&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::BasicColor&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t.Fg) , ';', static_cast(t.Bg), 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::Color24bFG&) override { /*m_Buffer->BasicWriteType("\033[38;2;", t.R, ';', t.G, ';', t.B, 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::Color24bBG&) override { /*m_Buffer->BasicWriteType("\033[48;2;", t.R, ';', t.G, ';', t.B, 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::Color24b&) override { /*m_Buffer->BasicWriteType("\033[38;2;", t.Fg.R, ';', t.Fg.G, ';', t.Fg.B, "; 48; 2;", t.Bg.R, ';', t.Bg.G, ';', t.Bg.B, 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::ColorCubeFG&) override { /*m_Buffer->BasicWriteType("\033[38;5;", t.GetColorRef(), 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::ColorCubeBG&) override { /*m_Buffer->BasicWriteType("\033[48;5;", t.GetColorRef(), 'm');*/ } + void ExecuteColor(const TextProperties::TextColor::ColorCube&) override { /*m_Buffer->BasicWriteType("\033[48;5;", t.Fg.GetColorRef(), ";48;5;", t.Bg.GetColorRef(), 'm');*/ } + + public: + void ResetFront() override { /*m_Buffer->BasicWriteType('\033', '[', TextProperties::TextFront::FrontID::DefaultFrontID, 'm');*/ } + void ExecuteFront(const TextProperties::TextFront::FrontID&) override { /*m_Buffer->BasicWriteType('\033', '[', t.ID, 'm');*/ } + + public: + void ResetStyle() override { /*m_Buffer->BasicWriteType('\033', '[', 0, 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Intensity&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Italic&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Underline&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color&) override { /*m_Buffer->BasicWriteType("\033[59m");*/ } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::ColorCube&) override { /*m_Buffer->BasicWriteType("\033[58;5;", t.GetColorRef(), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color24b&) override { /*m_Buffer->BasicWriteType("\033[58;2;", t.R, ';', t.G, ';', t.B, 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Blink&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Inverted&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Ideogram&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + void ExecuteStyle(const TextProperties::TextStyle::Script&) override { /*m_Buffer->BasicWriteType('\033', '[', static_cast(t), 'm');*/ } + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserNOTextPropertiesExecutor.h b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserNOTextPropertiesExecutor.h new file mode 100644 index 0000000..6ed6b9c --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/ParserTextPropertiesExecutor/ParserNOTextPropertiesExecutor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "IParserTextPropertiesExecutor.h" + +namespace ProjectCore::FMT::Detail +{ + template + class ParserNOTextPropertiesExecutor : public IParserTextPropertiesExecutor + { + public: + ~ParserNOTextPropertiesExecutor() override = default; + + public: + using Base = IParserTextPropertiesExecutor; + using Base::SetContext; + + protected: + using Base::m_Context; + + public: + void AllPropertiesReset() override {} + + public: + void ResetColor() override {} + void ExecuteColor(const TextProperties::TextColor::BasicColorFG&) override {} + void ExecuteColor(const TextProperties::TextColor::BasicColorBG&) override {} + void ExecuteColor(const TextProperties::TextColor::BasicColor&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24bFG&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24bBG&) override {} + void ExecuteColor(const TextProperties::TextColor::Color24b&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCubeFG&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCubeBG&) override {} + void ExecuteColor(const TextProperties::TextColor::ColorCube&) override {} + + public: + void ResetFront() override {} + void ExecuteFront(const TextProperties::TextFront::FrontID&) override {} + + public: + void ResetStyle() override {} + void ExecuteStyle(const TextProperties::TextStyle::Intensity&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Italic&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Underline&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::ColorCube&) override {} + void ExecuteStyle(const TextProperties::TextStyle::UnderlineColor::Color24b&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Blink&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Inverted&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Ideogram&) override {} + void ExecuteStyle(const TextProperties::TextStyle::Script&) override {} + }; +} diff --git a/src/ProjectCore/FMT/Context/ParserContext/ParserType.h b/src/ProjectCore/FMT/Context/ParserContext/ParserType.h new file mode 100644 index 0000000..93f8065 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/ParserType.h @@ -0,0 +1,36 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +#define PROJECTCORE_PARSER_DECLARED +namespace ProjectCore::FMT +{ + template> + struct ParserType { + static inline bool Parse(T&, ParserContext&) { +#ifdef UNKOWN_TYPE_MESSAGE + // FIXME + throw Detail::FMTShouldNotEndHere{}; +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::FMTShouldNotEndHere{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + // FIXME + throw Detail::FMTShouldNotEndHere{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + return false; + } + }; + +} + +#define PROJECTCORE_AUTO_PARSER(Type, fmt, ...) template\ + struct ProjectCore::FMT::ParserType {\ + static bool Parse(Type& value, ParserContext& context) {\ + return context.SubContextArrayFMT(fmt, __VA_ARGS__);\ + }\ + }; diff --git a/src/ProjectCore/FMT/Context/ParserContext/UtilityFunctions.h b/src/ProjectCore/FMT/Context/ParserContext/UtilityFunctions.h new file mode 100644 index 0000000..1620f56 --- /dev/null +++ b/src/ProjectCore/FMT/Context/ParserContext/UtilityFunctions.h @@ -0,0 +1,25 @@ +#pragma once + +#include "BasicParserContext.h" +#include "BasicParserContextCoreImpl.h" +#include "BasicParserContextParseImpl.h" + +namespace ProjectCore::FMT +{ + template + requires (Detail::CanBeUseForFMTBufferIn && Detail::CanBeUseForFMTBufferIn) + void Parse(const BufferData& bufferData, const FormatData& formatData, Args&& ...args) + { + using ContextType = Context::BasicParserContext::Type, typename Detail::FMTCharTypeFromBuffer::Type>; + auto contextArgsInterface = Detail::ParserContextArgsTupleInterface(std::forward(args)...); + Detail::BufferInProperties::Type> formatProperties(formatData); + Detail::FMTFormatBuffer::Type> format(formatProperties); + Detail::ParserANSITextPropertiesExecutor textPropertiesExecutor; + Detail::BufferInProperties::Type> bufferProperties(bufferData); + ContextType context(bufferProperties, textPropertiesExecutor); + context.Run(format, &contextArgsInterface); + context.Terminate(); + } + +} + diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBuffer.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBuffer.h new file mode 100644 index 0000000..b42e8b9 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBuffer.h @@ -0,0 +1,113 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BasicBuffer + { + public: + using StringView = std::basic_string_view>; + + protected: + CharBuffer* m_Buffer; + CharBuffer* m_CurrentPos; + CharBuffer* m_BufferEnd; // Point to the end char of the format + + protected: + inline CharBuffer* GetBuffer() noexcept { return m_Buffer; } + inline const CharBuffer* GetBuffer() const noexcept { return m_Buffer; } + inline CharBuffer* GetBufferCurrentPos() noexcept { return m_CurrentPos; } + inline const CharBuffer* GetBufferCurrentPos() const noexcept { return m_CurrentPos; } + inline CharBuffer* GetBufferEnd() noexcept { return m_BufferEnd; } + inline const CharBuffer* GetBufferEnd() const noexcept { return m_BufferEnd; } + inline std::size_t GetBufferSize() const noexcept { return static_cast(m_BufferEnd - m_Buffer); } + inline std::size_t GetBufferSizeLeft() const noexcept { return static_cast(m_BufferEnd - m_CurrentPos); } + inline std::size_t GetBufferCurrentSize() const noexcept { return static_cast(m_CurrentPos - m_Buffer); } + inline std::size_t GetBufferRemainingSize() const noexcept { return static_cast(m_BufferEnd - m_CurrentPos); } + + inline void SetBufferCurrentPos(CharBuffer* const pos) { if (pos >= GetBuffer() && pos <= GetBufferEnd()) m_CurrentPos = pos; } + + public: + BasicBuffer() noexcept + : m_Buffer(nullptr) + , m_CurrentPos(nullptr) + , m_BufferEnd(nullptr) + {} + + BasicBuffer(CharBuffer *const buffer, const std::size_t size) noexcept + : m_Buffer(buffer) + , m_CurrentPos(m_Buffer) + , m_BufferEnd(m_Buffer + size) + {} + + virtual ~BasicBuffer() noexcept = default; + + public: + template + void ReloadBuffer(OtherBuffer& buffer) noexcept + { + SetBuffer(buffer.GetBuffer(), buffer.GetBufferSize()); + SetBufferCurrentPos(buffer.GetBufferCurrentPos()); + } + + void SetBuffer(CharBuffer *const buffer, const std::size_t size) noexcept + { + m_Buffer = buffer; + m_CurrentPos = buffer; + m_BufferEnd = buffer + size; + } + + void SetBuffer(const std::basic_string_view>& buffer) noexcept + { + SetBuffer(buffer.data(), buffer.size()); + } + + public: + // Format + inline bool CanMoveForward() const noexcept { return m_CurrentPos + 1 <= m_BufferEnd; } + inline bool CanMoveForward(const std::size_t count) const noexcept { return m_CurrentPos + count <= m_BufferEnd; } + + inline bool CanMoveBackward() const noexcept { return m_CurrentPos - 1 >= m_Buffer; } + inline bool CanMoveBackward(const std::size_t count) const noexcept { return m_CurrentPos - count >= m_Buffer; } + inline bool IsNotOutOfBound() const noexcept { return m_CurrentPos < m_Buffer || m_CurrentPos >= m_BufferEnd; } + inline bool IsEndSimple() const noexcept { return m_CurrentPos >= m_BufferEnd; } + inline bool IsEnd() const noexcept { return IsEndSimple() || Get() == 0; } + + inline void CanMoveForwardThrow() const { if (CanMoveForward()) return; throw FMTBufferFull{}; } + inline void CanMoveForwardThrow(const std::size_t count) const { if (CanMoveForward(count)) return; throw FMTBufferFull{}; } + inline void CanMoveBackwardThrow() const { if (CanMoveBackward()) return; throw FMTBufferIndexOutOfRange{}; } + inline void CanMoveBackwardThrow(const std::size_t count) { if (CanMoveBackward(count)) return; throw FMTBufferIndexOutOfRange{}; } + inline void IsNotOutOfBoundThrow() const { if (IsNotOutOfBound()) return; throw FMTBufferIndexOutOfRange{}; } + inline void IsEndSimpleThrow() const { if (IsEndSimple()) return; throw FMTBufferEnd{}; } + inline void IsEndThrow() const { if (IsEnd()) return; throw FMTBufferEnd{}; } + + // Format base commands + inline void Forward() { CanMoveForwardThrow(); ++m_CurrentPos; } + inline void Forward(const std::size_t count) { CanMoveForwardThrow(count); m_CurrentPos += count; } + inline void ForwardNoCheck() noexcept { ++m_CurrentPos; } + inline void ForwardNoCheck(const std::size_t count) noexcept { m_CurrentPos += count; } + inline bool ForwardNoThrow() noexcept { if (CanMoveForward()) { ++m_CurrentPos; return true; } return false; } + inline bool ForwardNoThrow(const std::size_t count) noexcept { if (CanMoveForward(count)) { m_CurrentPos += count; return true; } return false; } + + inline void Backward() { CanMoveBackwardThrow(); --m_CurrentPos; } + inline void Backward(const std::size_t count) { CanMoveBackwardThrow(count); m_CurrentPos -= count; } + inline void BackwardNoCheck() noexcept { --m_CurrentPos; } + inline void BackwardNoCheck(const std::size_t count) noexcept { m_CurrentPos -= count; } + inline bool BackwardNoThrow() noexcept { if (CanMoveBackward()) { --m_CurrentPos; return true; } return false; } + inline bool BackwardNoThrow(const std::size_t count) noexcept { if (CanMoveBackward(count)) { m_CurrentPos -= count; return true; } return false; } + + inline void Reserve(const std::size_t count) { Forward(count); Backward(); } + + inline CharBuffer Get() const noexcept { return *m_CurrentPos; } + inline CharBuffer GetAndForward() { CanMoveForwardThrow(); return *m_CurrentPos++; } + inline CharBuffer GetAndForwardNoCheck() noexcept { return *m_CurrentPos++; } + inline CharBuffer GetAndBackward() { CanMoveBackwardThrow(); return *m_CurrentPos--; } + inline CharBuffer GetAndBackwardNoCheck() noexcept { return *m_CurrentPos--; } + inline CharBuffer GetNext() const { CanMoveForwardThrow(); return *(m_CurrentPos + 1); } + inline CharBuffer GetNextNoCheck() const noexcept { return *(m_CurrentPos + 1); } + inline CharBuffer GetPrev() const { CanMoveBackwardThrow(); return *(m_CurrentPos - 1); } + inline CharBuffer GetPrevNoCheck() const noexcept { return *(m_CurrentPos - 1); } + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h new file mode 100644 index 0000000..7e7e2d9 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h @@ -0,0 +1,352 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBuffer.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BasicBufferIn : public BasicBuffer + { + + protected: + using Base = BasicBuffer; + using Base::m_Buffer; + using Base::m_BufferEnd; + using Base::m_CurrentPos; + + public: + using typename Base::StringView; + + public: + using Base::GetBuffer; + using Base::GetBufferCurrentPos; + using Base::GetBufferEnd; + using Base::GetBufferSize; + using Base::GetBufferSizeLeft; + using Base::GetBufferCurrentSize; + using Base::GetBufferRemainingSize; + using Base::SetBufferCurrentPos; + + using Base::ReloadBuffer; + using Base::SetBuffer; + + public: + using Base::CanMoveForward; + using Base::CanMoveForwardThrow; + using Base::CanMoveBackward; + using Base::CanMoveBackwardThrow; + using Base::IsNotOutOfBound; + using Base::IsNotOutOfBoundThrow; + using Base::IsEnd; + using Base::IsEndThrow; + + using Base::Forward; + using Base::ForwardNoCheck; + using Base::ForwardNoThrow; + using Base::Backward; + using Base::BackwardNoCheck; + using Base::BackwardNoThrow; + using Base::Reserve; + + using Base::Get; + using Base::GetAndForward; + using Base::GetAndForwardNoCheck; + using Base::GetAndBackward; + using Base::GetAndBackwardNoCheck; + using Base::GetNext; + using Base::GetNextNoCheck; + using Base::GetPrev; + using Base::GetPrevNoCheck; + + public: + BasicBufferIn() noexcept + : Base() + {} + + BasicBufferIn(const BufferInProperties& properties) noexcept + : Base(properties.GetBuffer(), properties.GetBufferSize()) + {} + + BasicBufferIn(const CharBuffer* const buffer, const std::size_t bufferSize) noexcept + : Base(buffer, bufferSize) + {} + + BasicBufferIn(const CharBuffer* const begin, const CharBuffer* const end) noexcept + : Base(begin, static_cast(end - begin)) + {} + + ~BasicBufferIn() noexcept override = default; + + public: + template bool FastReadInt(T& i); + template bool FastReadUInt(T& i); + template bool FastReadFloat(T& i, FloatPrecision floatPrecision = FloatPrecision{}); + + template bool FastReadCharPtr(CharPtr* str, std::size_t sizeToCopy, bool isZeroEnded = true); + template inline bool FastReadCharArray(CharStr(&str)[SIZE], bool isZeroEnded = true) { return FastReadCharPtr(str, SIZE - (isZeroEnded ? 1 : 0), isZeroEnded); } + template inline bool FastReadCharBound(CharStr* begin, CharStr* end, bool isZeroEnded = true) { return FastReadCharPtr(begin, end - begin - (isZeroEnded ? 1 : 0), isZeroEnded); } + + template + bool FastReadCharPtrGlobber(std::basic_string_view globPattern, CharPtr* str, std::size_t sizeToCopy, bool isZeroEnded = true); + template + bool FastReadCharPtrRegex(std::basic_string_view regexPattern, CharPtr* str, std::size_t sizeToCopy, bool isZeroEnded = true); + template inline bool FastReadCharArrayGlobber(std::basic_string_view globPattern, CharStr(&str)[SIZE], bool isZeroEnded = true) { return FastReadCharPtrGlobber(globPattern, str, SIZE - (isZeroEnded ? 1 : 0), isZeroEnded); } + template inline bool FastReadCharBoundGlobber(std::basic_string_view globPattern, CharStr* begin, CharStr* end, bool isZeroEnded = true) { return FastReadCharPtrGlobber(globPattern, begin, end - begin - (isZeroEnded ? 1 : 0), isZeroEnded); } + template inline bool FastReadCharArrayRegex(std::basic_string_view regexPattern, CharStr(&str)[SIZE], bool isZeroEnded = true) { return FastReadCharPtrRegex(regexPattern, str, SIZE - (isZeroEnded ? 1 : 0), isZeroEnded); } + template inline bool FastReadCharBoundRegex(std::basic_string_view regexPattern, CharStr* begin, CharStr* end, bool isZeroEnded = true) { return FastReadCharPtrRegex(regexPattern, begin, end - begin - (isZeroEnded ? 1 : 0), isZeroEnded); } + + + public: + template void FastReadIntThrow (T& i) { if (FastReadInt(i) == false) throw FMTParseError{}; } + template void FastReadUIntThrow (T& i) { if (FastReadUInt(i) == false) throw FMTParseError{}; } + template void FastReadFloatThrow (T& i, FloatPrecision floatPrecision = FloatPrecision{}) { if (FastReadFloat(i, floatPrecision) == false) throw FMTParseError{}; } + template void FastReadCharPtrThrow(CharPtr* str, std::size_t sizeContainer, std::size_t sizeToWrite = 0) { if (FastReadCharPtr(str, sizeContainer, sizeToWrite) == false) throw FMTParseError{}; } + template inline void FastReadCharArrayThrow(CharStr(&str)[SIZE]) { if (FastReadCharArray(str) == false) throw FMTParseError{}; } + template inline void FastReadCharBoundThrow(CharStr* begin, CharStr* end) { if (FastReadCharBound(begin, end) == false) throw FMTParseError{}; } + + template + void FastReadCharPtrGlobberThrow(CharPtr* str, std::size_t sizeContainer, std::basic_string_view globPattern) { if (FastReadCharPtrGlobberThrow(str, sizeContainer, globPattern) == false) throw FMTParseError{}; } + template + void FastReadCharPtrRegexThrow(CharPtr* str, std::size_t sizeContainer, std::basic_string_view regexPattern) { if (FastReadCharPtrRegex(str, sizeContainer, regexPattern) == false) throw FMTParseError{}; } + template inline void FastReadCharArrayGlobberThrow(CharStr(&str)[SIZE], std::basic_string_view globPattern) { if (FastReadCharArrayGlobber(str, globPattern) == false) throw FMTParseError{}; } + template inline void FastReadCharBoundGlobberThrow(CharStr* begin, CharStr* end, std::basic_string_view globPattern) { if (FastReadCharBoundGlobber(begin, end, globPattern) == false) throw FMTParseError{}; } + template inline void FastReadStringViewGlobberThrow(std::basic_string_view& str, std::basic_string_view globPattern) { if (FastReadStringViewGlobber(str, globPattern) == false) throw FMTParseError{}; } + template inline void FastReadCharArrayRegexThrow(CharStr(&str)[SIZE], std::basic_string_view regexPattern) { if (FastReadCharArrayRegex(str, regexPattern) == false) throw FMTParseError{}; } + template inline void FastReadCharBoundRegexThrow(CharStr* begin, CharStr* end, std::basic_string_view regexPattern) { if (FastReadCharBoundRegex(begin, end, regexPattern) == false) throw FMTParseError{}; } + template inline void FastReadStringViewRegexThrow(std::basic_string_view& str, std::basic_string_view regexPattern) { if (FastReadStringViewRegex(str, regexPattern) == false) throw FMTParseError{}; } + + public: + // Format check + inline bool IsEqualTo(const CharBuffer c) const { return Get() == c; } + inline bool IsNotEqualTo(const CharBuffer c) const { return Get() != c; } + inline bool IsEqualToForward(const CharBuffer c) { if (IsEqualTo(c)) { Forward(); return true; } return false; } + inline bool IsNotEqualForward(const CharBuffer c) { if (IsNotEqualTo(c)) { Forward(); return true; } return false; } + template inline bool IsEqualTo(const CharBuffer c, const CharToTest ...ele) const { return IsEqualTo(c) || IsEqualTo(ele...); } + template inline bool IsEqualToForward(const CharToTest ...ele) { if (IsEqualTo(ele...)) { Forward(); return true; } return false; } + template inline bool IsNotEqualTo(const CharBuffer c, const CharToTest ...ele) const { return IsNotEqualTo(c) && IsNotEqualTo(ele...); } + template inline bool IsNotEqualForward(const CharToTest ...ele) { if (IsNotEqualTo(ele...)) { Forward(); return true; } return false; } + // Auto throw variant + inline bool IsEqualToThrow(const CharBuffer c) const { if (IsEqualTo(c)) return true; throw FMTParseError(); } + inline bool IsNotEqualToThrow(const CharBuffer c) const { if (IsNotEqualTo(c)) return true; throw FMTParseError(); } + inline bool IsEqualToForwardThrow(const CharBuffer c) { if (IsEqualToForward(c)) return true; throw FMTParseError(); } + inline bool Skip(const CharBuffer c) { return IsEqualToForwardThrow(c); } + inline bool IsNotEqualForwardThrow(const CharBuffer c) { if (IsNotEqualForward(c)) return true; throw FMTParseError(); } + template inline void IsEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (IsEqualTo(c, ele...)) return; throw FMTParseError(); } + template inline void IsEqualToForwardThrow(const CharToTest ...ele) { if (IsEqualToForward(ele...)) return; throw FMTParseError(); } + template inline void IsNotEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (IsNotEqualTo(c, ele...)) return; throw FMTParseError(); } + template inline void IsNotEqualForwardThrow(const CharToTest ...ele) { if (IsNotEqualForward(ele...)) return; throw FMTParseError(); } + + // Format Next check + inline bool NextIsEqualTo(const CharBuffer c) const { return GetNext() == c; } + inline bool NextIsNotEqualTo(const CharBuffer c) const { return GetNext() != c; } + inline bool NextIsEqualToForward(const CharBuffer c) { Forward(); if (IsEqualTo(c)) { return true; } BackwardNoCheck(); return false; } + inline bool NextIsNotEqualForward(const CharBuffer c) { Forward(); if (IsNotEqualTo(c)) { return true; } BackwardNoCheck(); return false; } + template inline bool NextIsEqualToForward(const CharToTest ...ele) { Forward(); if (IsEqualTo(ele...)) { return true; } BackwardNoCheck(); return false; } + template inline bool NextIsEqualTo(const CharToTest ...ele) const { Forward(); bool res = IsEqualTo(ele...); BackwardNoCheck(); return res; } + template inline bool NextIsNotEqualForward(const CharToTest ...ele) { Forward(); if (IsNotEqualTo(ele...)) { return true; } BackwardNoCheck(); return false; } + template inline bool NextIsNotEqualTo(const CharToTest ...ele) const { Forward(); bool res = IsNotEqualTo(ele...); BackwardNoCheck(); return res; } + // Auto throw variant + inline bool NextIsEqualToThrow(const CharBuffer c) const { if (NextIsEqualTo(c)) return true; throw FMTParseError(); } + inline bool NextIsNotEqualToThrow(const CharBuffer c) const { if (NextIsNotEqualTo(c)) return true; throw FMTParseError(); } + inline bool NextIsEqualToForwardThrow(const CharBuffer c) { if (NextIsEqualToForward(c)) return true; throw FMTParseError(); } + inline bool NextIsNotEqualForwardThrow(const CharBuffer c) { if (NextIsNotEqualForward(c)) return true; throw FMTParseError(); } + template inline void NextIsEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (NextIsEqualTo(c, ele...)) return; throw FMTParseError(); } + template inline void NextIsEqualToForwardThrow(const CharToTest ...ele) { if (NextIsEqualToForward(ele...)) return; throw FMTParseError(); } + template inline void NextIsNotEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (NextIsNotEqualTo(c, ele...)) return; throw FMTParseError(); } + template inline void NextIsNotEqualForwardThrow(const CharToTest ...ele) { if (NextIsNotEqualForward(ele...)) return; throw FMTParseError(); } + + // Format Next check + inline bool PrevIsEqualTo(const CharBuffer c) const { return GetPrev() == c; } + inline bool PrevIsNotEqualTo(const CharBuffer c) const { return GetPrev() != c; } + template inline bool PrevIsEqualTo(const CharToTest ...ele) const { Backward(); bool res = IsEqualTo(ele...); Forward(); return res; } + template inline bool PrevIsNotEqualTo(const CharToTest ...ele) const { Backward(); bool res = IsNotEqualTo(ele...); Forward(); return res; } + // Auto throw variant + inline bool PrevIsEqualToThrow(const CharBuffer c) const { if (PrevIsEqualTo(c)) return true; throw FMTParseError(); } + inline bool PrevIsNotEqualToThrow(const CharBuffer c) const { if (PrevIsNotEqualTo(c)) return true; throw FMTParseError(); } + template inline void PrevIsEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (PrevIsEqualTo(c, ele...)) return; throw FMTParseError(); } + template inline void PrevIsNotEqualToThrow(const CharBuffer c, const CharToTest ...ele) const { if (PrevIsNotEqualTo(c, ele...)) return; throw FMTParseError(); } + + public: + inline bool IsLowerCase() const { return Get() >= 'a' && Get() <= 'z'; } + inline bool IsUpperCase() const { return Get() >= 'A' && Get() <= 'Z'; } + inline bool IsADigit() const { return Get() >= '0' && Get() <= '9'; } + inline bool IsLowerCaseForward() const { if (IsLowerCase()) { Forward(); return true; } return false; } + inline bool IsUpperCaseForward() const { if (IsUpperCase()) { Forward(); return true; } return false; } + inline bool IsADigitForward() const { if (IsADigit()) { Forward(); return true; } return false; } + + inline void IsLowerCaseThrow() const { if (IsLowerCase()) return; throw FMTParseError(); } + inline void IsUpperCaseThrow() const { if (IsUpperCase()) return; throw FMTParseError(); } + inline void IsADigitThrow() const { if (IsADigit()) return; throw FMTParseError(); } + inline void IsLowerCaseForwardThrow() const { if (IsLowerCaseForward()) return; throw FMTParseError(); } + inline void IsUpperCaseForwardThrow() const { if (IsUpperCaseForward()) return; throw FMTParseError(); } + inline void IsADigitForwardThrow() const { if (IsADigitForward()) return; throw FMTParseError(); } + + protected: + template inline bool IsSameSeq(const CharBuffer* buffer, const CharToTest c, const Rest ...ele) const { if (*buffer != static_cast(c)) return false; if constexpr (sizeof... (ele) == 0) return true; return IsSameImpl(++buffer, ele...); } + public: + template inline bool IsSameSeq(const CharToTest ...ele) const { if (CanMoveForward(sizeof... (ele)) == false) return false; return IsSameSeqfImpl(m_Buffer, ele...); } + + template bool IsSameSeqForward(const CharToTest c, const Rest ...ele) + { + if (IsEqualToForward(c)) + { + if constexpr (sizeof...(ele) > 0) + { + bool res = IsSameSeqForward(ele...); + if (res == false) Backward(); + return res; + } + else + return true; + } + return false; + } + + template inline void IsSameSeqThrow(const CharToTest ...ele) const { if (IsSameSeq(ele...)) return; throw FMTParseError(); } + template inline void IsSameSeqForwardThrow(const CharToTest ...ele) { if (IsSameSeqForward(ele...)) return; throw FMTParseError(); } + + public: + template bool IsSame(const CharToTest* str, std::size_t size) const + { + if (str[size - 1] == 0) + --size; + if (size > GetBufferSizeLeft()) + return false; + + const CharBuffer* bufferStr = m_CurrentPos; + bool isSame = true; + while (isSame && size != 0 && *str != 0) { isSame = *bufferStr++ == *str++; --size; } + if (size != 0 && *str != 0) isSame = false; + return isSame; + } + + template inline bool IsSame(const CharToTest(&data)[SIZE]) const { return IsSame(data, SIZE); } + template inline bool IsSame(std::basic_string_view sv) const { return IsSame(sv.data(), sv.size()); } + template inline void IsSameThrow(const CharToTest* data, std::size_t size) const { if (IsSame(data, size)) return; throw FMTParseError(); } + template inline void IsSameThrow(const CharToTest(&data)[SIZE]) const { if (IsSame(data)) return; throw FMTParseError(); } + template inline void IsSameThrow(const std::basic_string_view& sv) const { if (IsSame(sv)) return; throw FMTParseError(); } + + template inline bool IsSameForward(const CharToTest* data, std::size_t size) { bool res = IsSame(data, size); if (res) ForwardNoCheck(data[size - 1] == 0 ? size - 1 : size); return res; } + template inline bool IsSameForward(const CharToTest(&data)[SIZE]) { bool res = IsSame(data, SIZE); if (res) ForwardNoCheck(data[SIZE - 1] == 0 ? SIZE - 1 : SIZE); return res; } + template inline bool IsSameForward(std::basic_string_view sv) { bool res = IsSame(sv); if (res) ForwardNoCheck(sv.size()); return res; } + template inline void IsSameForwardThrow(const CharToTest* data, std::size_t size) { if (IsSameForward(data, size)) return; throw FMTParseError(); } + template inline void IsSameForwardThrow(const CharToTest(&data)[SIZE]) { if (IsSameForward(data)) return; throw FMTParseError(); } + template inline void IsSameForwardThrow(const std::basic_string_view& sv) { if (IsSameForward(sv)) return; throw FMTParseError(); } + + static constexpr std::size_t GET_WORD_FROM_LIST_NOT_FOUND = (std::numeric_limits::max)(); + template + std::size_t GetWordFromList(const StringView (&data)[SIZE], const std::size_t defaultValue = GET_WORD_FROM_LIST_NOT_FOUND) + { + for (std::size_t idx = 0; idx < SIZE; ++idx) + if (IsSameForward(data[idx])) + return idx; + return defaultValue; + } + + + template + using TextTo = std::pair; + + template + T GetWordFromList(const TextTo (&data)[SIZE], T defaultValue = T{}) + { + for (std::size_t idx = 0; idx < SIZE; ++idx) + if (IsSameForward(data[idx].first)) + return data[idx].second; + return defaultValue; + } + + public: + inline void Ignore(const CharBuffer c) { IsEqualToForward(c); } + template inline void IgnoreAll(const CharToTest ...ele) { while (IsEqualTo(ele...) && CanMoveForward()) ForwardNoCheck(); } + + template inline void GoTo(const CharToTest ...ele) { while (IsNotEqualTo(ele...) && CanMoveForward()) ForwardNoCheck(); } + template inline void GoToForward(const CharToTest ...ele) { GoTo(ele...); Forward(); } + + public: + inline bool IsBlank() const { return IsEqualTo(' ', '\t', '\r'); } + inline bool IsBlankForward() const { if (IsBlank()) { Forward(); return true; } return false; } + inline void IsBlankThrow() const { if (IsBlank()) return; throw FMTParseError(); } + inline void IsBlankForwardThrow() const { if (IsBlankForward()) return; throw FMTParseError(); } + + inline void IgnoreSpace() { Ignore(' ', '\t'); } + inline void IgnoreBlank() { Ignore(' ', '\t', '\n'); } + + inline void IgnoreAllSpaces() { IgnoreAll(' ', '\t'); } + inline void IgnoreAllBlanks() { IgnoreAll(' ', '\t', '\n'); } + + public: + template + StringView GoToAndGetStr(const CharToTest ...args) + { + const CharBuffer* begin = GetBufferCurrentPos(); + GoTo(args...); + const CharBuffer* end = GetBufferCurrentPos(); + return StringView(begin, end); + } + + template + StringView GoToForwardAndGetStr(const CharToTest ...args) + { + const CharBuffer* begin = GetBufferCurrentPos(); + GoToForward(args...); + const CharBuffer* end = GetBufferCurrentPos(); + return StringView(begin, end); + } + + // FIXME + template + StringView ExecAndGetStr(const Args& ...args) + { + const CharBuffer* begin = GetBufferCurrentPos(); + Func(std::forward(args)...); + const CharBuffer* end = GetBufferCurrentPos(); + return StringView(begin, end); + } + + public: + // Basic types + template bool BasicReadType(T&) { return false; } + +#ifdef FMT_USE_STD_INTEGER + inline void BasicReadType(std::int8_t& i) { return FastReadIntThrow(i); } + inline void BasicReadType(std::uint8_t& i) { return FastReadUIntThrow(i); } + inline void BasicReadType(std::int16_t& i) { return FastReadIntThrow(i); } + inline void BasicReadType(std::uint16_t& i) { return FastReadUIntThrow(i); } + inline void BasicReadType(std::int32_t& i) { return FastReadIntThrow(i); } + inline void BasicReadType(std::uint32_t& i) { return FastReadUIntThrow(i); } + inline void BasicReadType(std::int64_t& i) { return FastReadIntThrow(i); } + inline void BasicReadType(std::uint64_t& i) { return FastReadUIntThrow(i); } +#else + inline void BasicReadType(const signed char i) { FastReadInt(i); } + inline void BasicReadType(const unsigned char i) { FastReadUInt(i); } + inline void BasicReadType(const short i) { FastReadInt(i); } + inline void BasicReadType(const unsigned short i) { FastReadUInt(i); } + inline void BasicReadType(const int i) { FastReadInt(i); } + inline void BasicReadType(const unsigned int i) { FastReadUInt(i); } + inline void BasicReadType(const long i) { FastReadInt(i); } + inline void BasicReadType(const unsigned long i) { FastReadUInt(i); } + inline void BasicReadType(const long long i) { FastReadInt(i); } + inline void BasicReadType(const unsigned long long i) { FastReadUInt(i); } +#endif + inline void BasicReadType(float& i) { return FastReadFloatThrow(i); } + inline void BasicReadType(double& i) { return FastReadFloatThrow(i); } + inline void BasicReadType(long double& i) { return FastReadFloatThrow(i); } + + inline void BasicReadType(char& i) { i = Base::GetAndForward(); return; } + inline void BasicReadType(wchar_t& i) { i = Base::GetAndForward(); return; } + inline void BasicReadType(char16_t& i) { i = Base::GetAndForward(); return; } + inline void BasicReadType(char32_t& i) { i = Base::GetAndForward(); return; } + + template inline void BasicReadType([[maybe_unused]] char(&i)[SIZE]) { /* TODO */ return; } + template inline void BasicReadType([[maybe_unused]] wchar_t(&i)[SIZE]) { /* TODO */ return; } + template inline void BasicReadType([[maybe_unused]] char16_t(&i)[SIZE]) { /* TODO */ return; } + template inline void BasicReadType([[maybe_unused]] char32_t(&i)[SIZE]) { /* TODO */ return; } + + template inline bool BasicReadType([[maybe_unused]] std::basic_string_view& i) { /* TODO */ return true; } + }; +} + +#include "Integer.h" +#include "String.h" diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/Integer.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/Integer.h new file mode 100644 index 0000000..91e8155 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/Integer.h @@ -0,0 +1,79 @@ +#pragma once + +#include "BasicBufferIn.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + template + template + bool BasicBufferIn::FastReadInt(T& i) { + T res = 0; + + bool sign = IsEqualToForward('-'); + if (!IsADigit()) + return false; + + while (IsADigit()) + res = res * static_cast(10) + static_cast(GetAndForward() - static_cast('0')); + + i = sign ? -res : res; + return true; + } + + template + template + bool BasicBufferIn::FastReadUInt(T& i) { + T res = (T)0; + + if(!IsADigit()) + return false; + + while (IsADigit()) + res = res * static_cast(10) + static_cast(GetAndForward() - static_cast('0')); + + i = res; + return true; + } + + template + template + bool BasicBufferIn::FastReadFloat(T& i, FloatPrecision floatPrecision) { + bool sign = IsEqualToForward('-'); + + bool hasIntPart = false; + if (IsNotEqualTo('.')) + { + hasIntPart = IsADigit(); + if (hasIntPart == false) return false; + T res = 0; + while (IsADigit()) + res = res * static_cast(10) + static_cast(GetAndForward() - static_cast('0')); + i = sign ? -res : res; + } + + if (IsEqualToForward('.') == false) return hasIntPart; + + if (floatPrecision.IsDefault() || floatPrecision == 0) + while (IsADigit() && IsEnd() == false) ForwardNoCheck(); + else + { + while (IsADigit() && floatPrecision > 0 && IsEnd() == false) + { + ForwardNoCheck(); + floatPrecision--; + } + } + BackwardNoCheck(); + + T dec = (T)0; + while (IsADigit()) + { + dec += static_cast(GetAndBackwardNoCheck() - '0'); + dec /= 10; + } + i += dec; + return true; + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/String.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/String.h new file mode 100644 index 0000000..bb0fee1 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferIn/String.h @@ -0,0 +1,43 @@ +#pragma once + +#include "BasicBufferIn.h" +#include "ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + bool BasicBufferIn::FastReadCharPtr(CharPtr* str, std::size_t sizeToCopy, bool isZeroEnded) + { + if (CanMoveForward(sizeToCopy) == false) + return FastReadCharPtr(str, GetBufferRemainingSize(), isZeroEnded); + + // TODO : Opti with bigger types + while (sizeToCopy-- != 0) + *str++ = GetAndForward(); + if (isZeroEnded) + *str = 0; + + return true; + } + + template + template + bool BasicBufferIn::FastReadCharPtrGlobber(std::basic_string_view globPattern, CharPtr* str, std::size_t sizeToCopy, [[maybe_unused]] bool isZeroEnded) + { + BasicBufferIn globber(globPattern); + const CharBuffer* begin = GetBufferCurrentPos(); + Globber::BufferInExecGlob(*this, globber); + const CharBuffer* end = GetBufferCurrentPos(); + + BasicBufferIn subContext(begin, end); + return subContext.FastReadCharPtr(str, sizeToCopy); + } + + template + template + bool BasicBufferIn::FastReadCharPtrRegex([[maybe_unused]] std::basic_string_view regexPattern, [[maybe_unused]] CharPtr* str, [[maybe_unused]] std::size_t sizeToCopy, [[maybe_unused]] bool isZeroEnded) + { + throw FMTImplError{}; + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h new file mode 100644 index 0000000..44c60f0 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h @@ -0,0 +1,230 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBuffer.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/BasicBufferOutManager.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BasicBufferOut : public BasicBuffer + { + protected: + using Base = BasicBuffer; + using Base::m_Buffer; + using Base::m_BufferEnd; + using Base::m_CurrentPos; + + public: + using typename Base::StringView; + + public: + using Base::GetBuffer; + using Base::GetBufferCurrentPos; + using Base::GetBufferEnd; + using Base::GetBufferSize; + using Base::GetBufferCurrentSize; + using Base::GetBufferRemainingSize; + using Base::SetBufferCurrentPos; + + using Base::ReloadBuffer; + using Base::SetBuffer; + + public: + // using Base::CanMoveForward; + // using Base::CanMoveForwardThrow; + using Base::CanMoveBackward; + using Base::CanMoveBackwardThrow; + + using Base::IsNotOutOfBound; + using Base::IsNotOutOfBoundThrow; + using Base::IsEnd; + using Base::IsEndThrow; + + // using Base::Forward; + using Base::ForwardNoCheck; + // using Base::ForwardNoThrow; + using Base::Backward; + using Base::BackwardNoCheck; + using Base::BackwardNoThrow; + // using Base::Reserve; + + using Base::Get; + // using Base::GetAndForward; + using Base::GetAndForwardNoCheck; + using Base::GetAndBackward; + using Base::GetAndBackwardNoCheck; + // using Base::GetNext; + using Base::GetNextNoCheck; + using Base::GetPrev; + using Base::GetPrevNoCheck; + + public: + static constexpr char UPPER_HEX[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static constexpr char LOWER_HEX[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + protected: + BasicBufferOutManager* m_BufferOutManager; + + public: + inline BasicBufferOutManager* GetBufferOutManagerPtr() noexcept { return m_BufferOutManager; } + inline const BasicBufferOutManager* GetBufferOutManagerPtr() const noexcept { return m_BufferOutManager; } + + inline BasicBufferOutManager& GetBufferOutManager() noexcept { return *m_BufferOutManager; } + inline const BasicBufferOutManager& GetBufferOutManager() const noexcept { return *m_BufferOutManager; } + + public: + BasicBufferOut() noexcept + : Base() + , m_BufferOutManager(nullptr) + {} + + BasicBufferOut(BasicBufferOutManager& bufferOutManager) + : Base() + , m_BufferOutManager(&bufferOutManager) + { + m_BufferOutManager->BeginContext(); + SetBuffer(m_BufferOutManager->GetBuffer(), m_BufferOutManager->GetBufferSize()); + SetBufferCurrentPos(m_BufferOutManager->GetBuffer()); + } + + ~BasicBufferOut() noexcept override = default; + + public: + void SetBufferOutManager(BasicBufferOutManager& bufferOutManager) + { + m_BufferOutManager = &bufferOutManager; + if (m_BufferOutManager == nullptr) + throw Detail::FMTShouldNotEndHere{}; + + m_BufferOutManager->BeginContext(); + SetBuffer(m_BufferOutManager->GetBuffer(), m_BufferOutManager->GetBufferSize()); + SetBufferCurrentPos(m_BufferOutManager->GetBuffer()); + } + + + void EndContext() + { + m_BufferOutManager->EndContext(GetBufferCurrentSize()); + } + + public: + // TODO : need to have throw version od those to have secure call + template void FastWriteInt (T i); + template void FastWriteUInt (T i); + template void FastWriteFloat (T i, FloatPrecision floatPrecision = FloatPrecision{}); + + template void FastWriteIntAsBin (T i, DigitSize digitSize = DigitSize::DEFAULT, bool prefix = true); + template void FastWriteIntAsHex (T i, DigitSize digitSize = DigitSize::DEFAULT, bool prefix = true, Detail::PrintStyle uppercase = PrintStyle::Nothing); + template void FastWriteIntAsOct (T i, DigitSize digitSize = DigitSize::DEFAULT, bool prefix = true); + + template + void FastWriteCharPtr(const CharStr* str, std::size_t size); + + template inline void FastWriteCharPtrNSize(const CharStr* str) { FastWriteStringView(std::basic_string_view(str)); } + template inline void FastWriteCharArray(const CharStr(&str)[SIZE]) { FastWriteCharPtr(str, str[SIZE - 1] == 0 ? SIZE - 1 : SIZE); } + template inline void FastWriteCharBound(const CharStr* begin, const CharStr* end) { FastWriteCharPtr(begin, static_cast(end - begin)); } + template inline void FastWriteStringView(const std::basic_string_view& str) { FastWriteCharPtr(str.data(), str.size()); } + template inline void FastWriteString(const std::basic_string& str) { FastWriteCharPtr(str.data(), str.size()); } + + protected: + template + static DataType GetNumberOfDigitDec(T value); + + public: + bool AddSize(const std::size_t count) + { + if (m_BufferOutManager == nullptr) + throw Detail::FMTShouldNotEndHere{}; + if (m_CurrentPos > m_BufferEnd) + throw Detail::FMTBufferError{}; + std::size_t currentSize = GetBufferCurrentSize(); + if (m_BufferOutManager->AddSize(count) == false) + return false; + SetBuffer(m_BufferOutManager->GetBuffer(), m_BufferOutManager->GetBufferSize()); + SetBufferCurrentPos(m_BufferOutManager->GetBuffer() + currentSize); + return true; + } + + inline bool CanMoveForward() { if (m_CurrentPos + 1 <= m_BufferEnd) return true; return AddSize(1); } + inline bool CanMoveForward(const auto count) { if (m_CurrentPos + count <= m_BufferEnd) return true; return AddSize(static_cast(count));} + inline void CanMoveForwardThrow() { if (CanMoveForward()) return; throw FMTBufferFull{}; } + inline void CanMoveForwardThrow(const auto count) { if (CanMoveForward(count)) return; throw FMTBufferFull{}; } + + inline void Forward() { CanMoveForwardThrow(); ++m_CurrentPos; } + inline void Forward(const auto count) { CanMoveForwardThrow(count); m_CurrentPos += count; } + inline void ForwardNoThrow() { if (CanMoveForward()) ++m_CurrentPos; } + inline void ForwardNoThrow(const auto count) { if (CanMoveForward(count)) m_CurrentPos += count; } + inline CharBuffer GetAndForward() { CanMoveForwardThrow(); return *m_CurrentPos++; } + inline CharBuffer GetNext() { CanMoveForwardThrow(); return *(m_CurrentPos + 1); } + inline void Reserve(const auto count) { Forward(count); Backward(); } + + public: + inline void SetChar(const CharBuffer c) { *m_CurrentPos = c; } + inline void PushBack(const CharBuffer c) { if (CanMoveForward()) *m_CurrentPos++ = c; } + inline void PushReverse(const CharBuffer c) { if (CanMoveBackward()) *m_CurrentPos-- = c; } + inline void PushBackNoCheck(const CharBuffer c) { *m_CurrentPos++ = c; } + inline void PushReverseNoCheck(const CharBuffer c) { *m_CurrentPos-- = c; } + inline void PushBack(const CharBuffer c, auto count) { if (CanMoveForward(count)) while (count-- > 0) PushBackNoCheck(c); } + inline void PushReverse(const CharBuffer c, auto count) { if (CanMoveBackward(count)) while (count-- > 0) PushReverseNoCheck(c); } + + inline void PushBackEndChar() { PushBack('\0'); } + inline void AddSpaces(const auto count) { PushBack(' ', count); } + + protected: + template + inline void PushBackSeqImpl(const CharBuffer c, const Rest... rest) { PushBackNoCheck(c); if constexpr (sizeof...(rest) > 0) PushBackSeqImpl(rest...); } + + public: + template + inline void PushBackSeq(const CharToPush... ele) { if(CanMoveForward(sizeof...(ele))) return PushBackSeqImpl(ele...); } + + public: + // Basic types + template + inline void BasicWriteType(Type&& type, Rest&& ...rest) { BasicWriteType(type); if constexpr (sizeof...(rest) > 0) BasicWriteType(std::forward(rest)...); } + + template void BasicWriteType(T) {} + +#if FMT_USE_STD_INTEGER + inline void BasicWriteType(const std::int8_t i) { FastWriteInt(i); } + inline void BasicWriteType(const std::uint8_t i) { FastWriteUInt(i); } + inline void BasicWriteType(const std::int16_t i) { FastWriteInt(i); } + inline void BasicWriteType(const std::uint16_t i) { FastWriteUInt(i); } + inline void BasicWriteType(const std::int32_t i) { FastWriteInt(i); } + inline void BasicWriteType(const std::uint32_t i) { FastWriteUInt(i); } + inline void BasicWriteType(const std::int64_t i) { FastWriteInt(i); } + inline void BasicWriteType(const std::uint64_t i) { FastWriteUInt(i); } +#else + inline void BasicWriteType(const signed char i) { FastWriteInt(i); } + inline void BasicWriteType(const unsigned char i) { FastWriteUInt(i); } + inline void BasicWriteType(const short i) { FastWriteInt(i); } + inline void BasicWriteType(const unsigned short i) { FastWriteUInt(i); } + inline void BasicWriteType(const int i) { FastWriteInt(i); } + inline void BasicWriteType(const unsigned int i) { FastWriteUInt(i); } + inline void BasicWriteType(const long i) { FastWriteInt(i); } + inline void BasicWriteType(const unsigned long i) { FastWriteUInt(i); } + inline void BasicWriteType(const long long i) { FastWriteInt(i); } + inline void BasicWriteType(const unsigned long long i) { FastWriteUInt(i); } +#endif + + inline void BasicWriteType(const float i) { FastWriteFloat(i); } + inline void BasicWriteType(const double i) { FastWriteFloat(i); } + inline void BasicWriteType(const long double i) { FastWriteFloat(i); } + + inline void BasicWriteType(const char i) { PushBack(i); } + inline void BasicWriteType(const wchar_t i) { PushBack(i); } + inline void BasicWriteType(const char16_t i) { PushBack(i); } + inline void BasicWriteType(const char32_t i) { PushBack(i); } + + template inline void BasicWriteType(const char (&i)[SIZE]) { FastWriteCharArray(i); } + template inline void BasicWriteType(const wchar_t (&i)[SIZE]) { FastWriteCharArray(i); } + template inline void BasicWriteType(const char16_t (&i)[SIZE]) { FastWriteCharArray(i); } + template inline void BasicWriteType(const char32_t (&i)[SIZE]) { FastWriteCharArray(i); } + + template inline void BasicWriteType(const std::basic_string_view& i) { FastWriteString(i); } + }; +} + +#include "Integer.h" +#include "String.h" +#include "Internal.h" diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Integer.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Integer.h new file mode 100644 index 0000000..412d074 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Integer.h @@ -0,0 +1,167 @@ +#pragma once + +#include "BasicBufferOut.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + template + template + void BasicBufferOut::FastWriteInt(T i) { + if (i == 0) { PushBack('0'); return; } + if (i < 0) { PushBack('-'); i = -i; } + + DataType nbDigit = GetNumberOfDigitDec(i); + Reserve(nbDigit); + while (i > 0) { PushReverseNoCheck(i % 10 + '0'); i /= 10; } + Forward(nbDigit + 1); + } + + template + template + void BasicBufferOut::FastWriteUInt(T i) { + if (i == 0) { PushBack('0'); return; } + + DataType nbDigit = GetNumberOfDigitDec(i); + Reserve(nbDigit); + while (i > 0) { PushReverseNoCheck(i % 10 + '0'); i /= 10; } + Forward(nbDigit + 1); + } + + template + template + void BasicBufferOut::FastWriteFloat(T i, FloatPrecision nbDecimal) { + if (i == 0) { PushBack('0'); return; } + if (i < 0) { PushBack('-'); i = -i; } + + T k = std::trunc(i); + i = i - k; + DataType nbDigit = GetNumberOfDigitDec(k); + Reserve(nbDigit); + DataType nbDigit_ = nbDigit; + while (nbDigit_ > 0) + { + PushReverseNoCheck(char(std::fmod(k, 10)) + '0'); + k /= 10; + nbDigit_--; + } + Forward(nbDigit + 1); + PushBack('.'); + + nbDecimal.SetToBasicSizeIfDefault(); + + while (nbDecimal-- != 0) + { + CharBuffer intPart = static_cast(std::trunc(i *= 10)); + PushBack(intPart + '0'); + i -= intPart; + } + } + + template + template + void BasicBufferOut::FastWriteIntAsBin(T i, DigitSize digitSize, bool prefix) { + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(sizeof(T) * 8); + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if ((cpyI & 1) != 0) lastPosWithData = k; + cpyI = cpyI >> 1; + } + digitSize -= lastPosWithData; + } + + if (prefix) + { + PushBack('0'); + PushBack('b'); + } + + Reserve(digitSize); + DataType k = digitSize + 1; + while (--k != 0) { + if (i & 1) PushReverseNoCheck('1'); + else PushReverseNoCheck('0'); + i = i >> 1; + } + Forward(digitSize + 1); + + } + + template + template + void BasicBufferOut::FastWriteIntAsHex(T i, DigitSize digitSize, bool prefix, Detail::PrintStyle uppercase) { + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(sizeof(T) * 2); + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if ((cpyI & 0b1111) != 0) lastPosWithData = k; + cpyI = cpyI >> 4; + } + digitSize -= lastPosWithData; + } + + if (prefix) + { + PushBack('0'); + PushBack('x'); + } + + // Print value + Reserve(digitSize); + DataType k = digitSize + 1; + if (uppercase == PrintStyle::LowerCase) + while (--k != 0) { PushReverseNoCheck(LOWER_HEX[i & 0b1111]); i = i >> 4; } + else + while (--k != 0) { PushReverseNoCheck(UPPER_HEX[i & 0b1111]); i = i >> 4; } + Forward(digitSize + 1); + } + + template + template + void BasicBufferOut::FastWriteIntAsOct(T i, DigitSize digitSize, bool prefix) { + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(std::ceil(static_cast(sizeof(T) * 8) / 3)); + + if (prefix) + { + PushBack('0'); + PushBack('o'); + } + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if ((cpyI & 0b111) != 0) lastPosWithData = k; + cpyI = cpyI >> 3; + } + digitSize -= lastPosWithData; + } + + // Print value + Reserve(digitSize); + DataType k = digitSize + 1; + while (--k != 0) { PushReverseNoCheck((i & 0b111) + '0'); i = i >> 3; } + Forward(digitSize + 1); + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Internal.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Internal.h new file mode 100644 index 0000000..004f8da --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/Internal.h @@ -0,0 +1,27 @@ +#pragma once + +#include "BasicBufferOut.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + DataType BasicBufferOut::GetNumberOfDigitDec(T value) + { + if constexpr (std::numeric_limits::is_signed) + { + if (value < 0) value = -value; + } + DataType nb = 0; + while(true) { + if (value < 10) return nb + 1; + else if(value < 100) return nb + 2; + else if (value < 1000) return nb + 3; + else if (value < 10000) return nb + 4; + else { + value /= static_cast(10000); + nb += 4; + } + } + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/String.h b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/String.h new file mode 100644 index 0000000..07f34a6 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BasicBufferOut/String.h @@ -0,0 +1,17 @@ +#pragma once + +#include "BasicBufferOut.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + inline void BasicBufferOut::FastWriteCharPtr(const CharStr* str, std::size_t size) { + if (CanMoveForward(size) == false) + return FastWriteCharPtr(str, GetBufferRemainingSize()); + + // TODO : Opti with bigger types + while (size-- != 0 && *str != 0) + PushBackNoCheck(*str++); + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h b/src/ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h new file mode 100644 index 0000000..ab40073 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h @@ -0,0 +1,32 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BufferInProperties + { + public: + template + BufferInProperties(const CharType (&format)[SIZE]) : m_Buffer(format), m_BufferSize(format[SIZE - 1] == 0 ? SIZE - 1 : SIZE) {} + BufferInProperties(const std::basic_string_view& format) : m_Buffer(format.data()), m_BufferSize(format.size()) {} + BufferInProperties(const std::basic_string& format) : m_Buffer(format.data()), m_BufferSize(format.size()) {} + BufferInProperties(const CharType* const buffer, const std::size_t bufferSize) : m_Buffer(buffer), m_BufferSize(bufferSize) {} + + public: + const CharType* GetBuffer() const { return m_Buffer; } + std::size_t GetBufferSize() const { return m_BufferSize; } + + public: + const CharType* const m_Buffer; + const std::size_t m_BufferSize; + }; + + template + concept CanBeUseForFMTBufferIn = requires() + { + requires !std::is_same_v::Type, void>; + // requires std::is_constructible_v::Type>, BufferDataType>; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/BasicBufferOutManager.h b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/BasicBufferOutManager.h new file mode 100644 index 0000000..85e2b24 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/BasicBufferOutManager.h @@ -0,0 +1,44 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + template + class BasicBufferOutManager + { + public: + virtual ~BasicBufferOutManager() = default; + + protected: + virtual void BeginContextImpl() {} + virtual void EndContextImpl(const std::size_t /* totalGeneratedLength */) {} + + public: + void BeginContext() { BeginContextImpl(); } + void EndContext(std::size_t totalGeneratedLength) { EndContextImpl(totalGeneratedLength); SetLastGeneratedDataSize(totalGeneratedLength); } + + public: + virtual CharType* GetBuffer() = 0; + virtual const CharType* GetBuffer() const = 0; + virtual std::size_t GetBufferSize() const = 0; + + public: + virtual bool AddSize(const std::size_t count) = 0; + + public: + std::basic_string_view GetLastGeneratedStringView() const { return std::basic_string_view(GetBuffer(), m_LastGeneratedDataSize); } + operator std::basic_string_view() const { return GetLastGeneratedStringView(); } + std::basic_string GetLastGeneratedString() const { return std::basic_string(GetBuffer(), m_LastGeneratedDataSize); } + operator std::basic_string() const { return GetLastGeneratedString(); } + + public: + std::size_t GetLastGeneratedDataSize() const { return m_LastGeneratedDataSize; } + + private: + void SetLastGeneratedDataSize(const std::size_t size) { m_LastGeneratedDataSize = size; } + + protected: + std::size_t m_LastGeneratedDataSize{ 0 }; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h new file mode 100644 index 0000000..8205e59 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h @@ -0,0 +1,110 @@ +#pragma once + +#include "BasicBufferOutManager.h" + +#include +#include +#include + +namespace ProjectCore::FMT::Detail +{ + template + class DynamicBufferOutManager : public BasicBufferOutManager + { + public: + DynamicBufferOutManager(std::size_t beginSize = DEFAULT_BEGIN_SIZE) + { + m_Buffer.reset(new CharType[beginSize]); + m_BufferSize = beginSize; + } + ~DynamicBufferOutManager() override = default; + + public: + static constexpr std::size_t DEFAULT_BEGIN_SIZE = 128; + static constexpr std::size_t GROW_UP_BUFFER_SIZE = 2; + static constexpr bool DEBUG_RESIZE = false; + + public: + CharType* GetBuffer() override { return m_Buffer.get(); } + const CharType* GetBuffer() const override { return m_Buffer.get(); } + std::size_t GetBufferSize() const override { return m_BufferSize; } + + public: + bool AddSize(const std::size_t count) override { return Resize(count + m_BufferSize); } + bool Resize(const std::size_t targetBufferSize); + + protected: + std::unique_ptr m_Buffer; + std::size_t m_BufferSize; + }; + + template + class ShrinkDynamicBufferOutManager : public DynamicBufferOutManager + { + public: + using Base = DynamicBufferOutManager; + using Base::DEFAULT_BEGIN_SIZE; + using Base::GROW_UP_BUFFER_SIZE; + using Base::DEBUG_RESIZE; + + using Base::GetBuffer; + using Base::GetBufferSize; + using Base::Resize; + + using Base::m_Buffer; + using Base::m_BufferSize; + + static constexpr float MEAN_SIZE_OVERFLOW = 4.2f; + static constexpr float MEAN_SIZE_RESIZE = 1.4f; + static constexpr float MEAN_CALCFACT_OLD = 5; + static constexpr float MEAN_CALCFACT_LAST = 1; + + public: + ShrinkDynamicBufferOutManager(std::size_t beginSize = DEFAULT_BEGIN_SIZE) + : Base(beginSize) + , m_MeanGeneratedSize(beginSize) + {} + + ~ShrinkDynamicBufferOutManager() override = default; + + protected: + void BeginContextImpl() override { ShrinkIfNeeded(); } + void EndContextImpl(std::size_t totalGeneratedLength) override + { m_MeanGeneratedSize = (m_MeanGeneratedSize * MEAN_CALCFACT_OLD + totalGeneratedLength * MEAN_CALCFACT_LAST) / (MEAN_CALCFACT_OLD + MEAN_CALCFACT_LAST); } + + public: + void ShrinkIfNeeded() + { + if (m_BufferSize > static_cast(m_MeanGeneratedSize * MEAN_SIZE_OVERFLOW)) + Resize(static_cast(m_MeanGeneratedSize * MEAN_SIZE_RESIZE)); + } + + private: + std::size_t m_MeanGeneratedSize; + }; + + template + bool DynamicBufferOutManager::Resize(const std::size_t targetBufferSize) { + std::size_t newBufferSize = targetBufferSize; + + if (m_BufferSize < targetBufferSize) + { + newBufferSize = m_BufferSize; + while(newBufferSize < targetBufferSize) + newBufferSize *= GROW_UP_BUFFER_SIZE; + } + + CharType* safeBuffer = new CharType[newBufferSize]; + if (safeBuffer == nullptr) return false; + + std::memcpy(safeBuffer, m_Buffer.get(), std::min(newBufferSize, m_BufferSize)); + + if constexpr (DEBUG_RESIZE) + std::cout << "Resize from " << m_BufferSize << " to " << newBufferSize << std::endl; + + m_Buffer.reset(safeBuffer); + m_BufferSize = newBufferSize; + + return true; + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h new file mode 100644 index 0000000..e240b1e --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h @@ -0,0 +1,36 @@ +#pragma once + +#include "BasicBufferOutManager.h" + +namespace ProjectCore::FMT::Detail +{ + template + class GivenBufferOutManager : public BasicBufferOutManager + { + public: + template + GivenBufferOutManager(CharType (&buffer)[SIZE]) + : m_Buffer(buffer) + , m_BufferSize(SIZE) + {} + + GivenBufferOutManager(CharType* buffer, std::size_t bufferSize) + : m_Buffer(buffer) + , m_BufferSize(bufferSize) + {} + + ~GivenBufferOutManager() override = default; + + public: + CharType* GetBuffer() override { return m_Buffer; } + const CharType* GetBuffer() const override { return m_Buffer; } + std::size_t GetBufferSize() const override { return m_BufferSize; } + + public: + bool AddSize(const std::size_t /* count */) override { return false; } + + private: + CharType* m_Buffer; + std::size_t m_BufferSize; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h new file mode 100644 index 0000000..5a33d0b --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h @@ -0,0 +1,24 @@ +#pragma once + +#include "BasicBufferOutManager.h" + +namespace ProjectCore::FMT::Detail +{ + template + class StaticBufferOutManager : public BasicBufferOutManager + { + public: + ~StaticBufferOutManager() override = default; + + public: + CharType* GetBuffer() override { return m_Buffer; } + const CharType* GetBuffer() const override { return m_Buffer; } + std::size_t GetBufferSize() const override { return Count; } + + public: + bool AddSize(const std::size_t) override { return false; } + + private: + CharType m_Buffer[Count]; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h new file mode 100644 index 0000000..3345dd6 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h @@ -0,0 +1,202 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h" + +namespace ProjectCore::FMT::Detail +{ + template + class FMTBufferIn : public BasicBufferIn + { + protected: + using Base = ProjectCore::FMT::Detail::BasicBufferIn; + using Base::m_Buffer; + using Base::m_BufferEnd; + using Base::m_CurrentPos; + + public: + using typename Base::StringView; + + public: + using Base::GetBuffer; + using Base::GetBufferCurrentPos; + using Base::GetBufferEnd; + using Base::GetBufferSize; + using Base::GetBufferCurrentSize; + using Base::GetBufferRemainingSize; + using Base::SetBufferCurrentPos; + + using Base::ReloadBuffer; + using Base::SetBuffer; + + public: + using Base::CanMoveForward; + using Base::CanMoveForwardThrow; + using Base::CanMoveBackward; + using Base::CanMoveBackwardThrow; + using Base::IsNotOutOfBound; + using Base::IsNotOutOfBoundThrow; + using Base::IsEnd; + using Base::IsEndThrow; + + using Base::Forward; + using Base::ForwardNoCheck; + using Base::ForwardNoThrow; + using Base::Backward; + using Base::BackwardNoCheck; + using Base::BackwardNoThrow; + using Base::Reserve; + + using Base::Get; + using Base::GetAndForward; + using Base::GetAndForwardNoCheck; + using Base::GetAndBackward; + using Base::GetAndBackwardNoCheck; + using Base::GetNext; + using Base::GetNextNoCheck; + using Base::GetPrev; + using Base::GetPrevNoCheck; + + public: + using Base::FastReadInt; + using Base::FastReadUInt; + using Base::FastReadFloat; + + using Base::FastReadIntThrow; + using Base::FastReadUIntThrow; + using Base::FastReadFloatThrow; + + using Base::FastReadCharPtrThrow; + using Base::FastReadCharArrayThrow; + using Base::FastReadCharBoundThrow; + + using Base::FastReadCharPtrGlobberThrow; + using Base::FastReadCharArrayGlobber; + using Base::FastReadCharBoundGlobber; + using Base::FastReadCharPtrRegex; + using Base::FastReadCharArrayRegex; + using Base::FastReadCharBoundRegex; + + using Base::BasicReadType; + + public: + using Base::IsEqualTo; + using Base::IsNotEqualTo; + using Base::IsEqualToForward; + using Base::IsNotEqualForward; + using Base::IsEqualToThrow; + using Base::IsNotEqualToThrow; + using Base::IsEqualToForwardThrow; + using Base::Skip; + using Base::IsNotEqualForwardThrow; + + using Base::NextIsEqualTo; + using Base::NextIsNotEqualTo; + using Base::NextIsEqualToForward; + using Base::NextIsNotEqualForward; + using Base::NextIsEqualToThrow; + using Base::NextIsNotEqualToThrow; + using Base::NextIsEqualToForwardThrow; + using Base::NextIsNotEqualForwardThrow; + + using Base::PrevIsEqualTo; + using Base::PrevIsNotEqualTo; + using Base::PrevIsEqualToThrow; + using Base::PrevIsNotEqualToThrow; + + using Base::IsLowerCase; + using Base::IsUpperCase; + using Base::IsADigit; + using Base::IsLowerCaseForward; + using Base::IsUpperCaseForward; + using Base::IsADigitForward; + using Base::IsLowerCaseThrow; + using Base::IsUpperCaseThrow; + using Base::IsADigitThrow; + using Base::IsLowerCaseForwardThrow; + using Base::IsUpperCaseForwardThrow; + using Base::IsADigitForwardThrow; + + + using Base::IsSameSeq; + using Base::IsSameSeqForward; + using Base::IsSameSeqThrow; + using Base::IsSameSeqForwardThrow; + using Base::IsSame; + using Base::IsSameForward; + using Base::IsSameThrow; + using Base::IsSameForwardThrow; + + using Base::GetWordFromList; + + using Base::Ignore; + using Base::IgnoreAll; + using Base::GoTo; + using Base::GoToForward; + + using Base::IsBlank; + using Base::IsBlankForward; + using Base::IsBlankThrow; + using Base::IsBlankForwardThrow; + + using Base::IgnoreBlank; + using Base::IgnoreSpace; + using Base::IgnoreAllBlanks; + using Base::IgnoreAllSpaces; + + public: + FMTBufferIn() : Base() {} + FMTBufferIn(const BufferInProperties& properties) : Base(properties) {} + + FMTBufferIn(const CharBuffer* const buffer, const std::size_t bufferSize) + : Base(buffer, bufferSize) + {} + + ~FMTBufferIn() override = default; + + public: + template void ReadInt (T& i, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + template void ReadUInt (T& i, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + template void ReadFloat (T& i, FloatPrecision floatPrecision = FloatPrecision{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + + template void ReadIntAsBin (T& i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool trueValue = false); + template void ReadIntAsHex (T& i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool trueValue = false, Detail::PrintStyle valueDes = PrintStyle::Nothing); + template void ReadIntAsOct (T& i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool trueValue = false); + + public: + template void ReadIntFormatData (T& i, const FormatData& formatData); + template void ReadUIntFormatData (T& i, const FormatData& formatData); + template void ReadFloatFormatData (T& i, const FormatData& formatData); + + + public: + template void ReadCharPtr(const CharStr* str, std::size_t sizeContainer, std::size_t sizeToWrite, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + + template inline void ReadCharArray(const CharStr(&str)[SIZE], ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { ReadCharPtr(str, SIZE, 0, st, shift, sp); } + template inline void ReadCharBound(const CharStr* begin, const CharStr* end, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { ReadCharPtr(begin, end - begin, 0, st, shift, sp); } + + protected: + template + void SkipShiftBeginSpace(const Detail::ShiftType st, const Detail::ShiftPrint sp, T& shift) { + if (sp.BeforeIsADigit() == false) + return; + if (st == ShiftType::Right || st == ShiftType::CenterLeft || st == ShiftType::CenterRight) + while (Base::Get() == ' ') { + Base::Forward(); + --shift; + } + } + + template + void SkipShiftEnd(const Detail::ShiftType st, const Detail::ShiftPrint, T& shift) { + if (st == ShiftType::Left || st == ShiftType::CenterLeft || st == ShiftType::CenterRight) + while (Base::Get() == ' ' && shift > 0) { + Base::Forward(); + --shift; + } + } + }; +} + +#include "Integer.h" +#include "FromFormatData.h" +#include "String.h" diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FromFormatData.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FromFormatData.h new file mode 100644 index 0000000..5821432 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FromFormatData.h @@ -0,0 +1,58 @@ +#pragma once + +#include "FMTBufferIn.h" +#include "Integer.h" + +namespace ProjectCore::FMT::Detail +{ + //------------------ Buffer Read Int ------------------// + template + template + void FMTBufferIn::ReadIntFormatData(T& i, const FormatData& formatData) { + if (formatData.HasSpec) { + switch (formatData.IntPrint) { + case ValueIntPrint::Dec: + if (formatData.ShiftType == ShiftType::Nothing) return FastReadIntThrow(i); + else return ReadInt(i, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + case ValueIntPrint::Bin: + return ReadIntAsBin(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + case ValueIntPrint::Hex: + return ReadIntAsHex(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue, formatData.PrintStyle); + case ValueIntPrint::Oct: + return ReadIntAsOct(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + } + } + return FastReadIntThrow(i); + } + + //------------------ Buffer Read UInt ------------------// + template + template + void FMTBufferIn::ReadUIntFormatData(T& i, const FormatData& formatData) { + if (formatData.HasSpec) { + switch (formatData.IntPrint) { + case ValueIntPrint::Dec: + if (formatData.ShiftType == ShiftType::Nothing) return FastReadUIntThrow(i); + else return ReadUInt(i, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + case ValueIntPrint::Bin: + return ReadIntAsBin(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + case ValueIntPrint::Hex: + return ReadIntAsHex(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue, formatData.PrintStyle); + case ValueIntPrint::Oct: + return ReadIntAsOct(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + } + } + return FastReadUIntThrow(i); + } + + //------------------ Buffer Read Float ------------------// + template + template + void FMTBufferIn::ReadFloatFormatData(T& i, const FormatData& formatData) { + if (formatData.HasSpec) { + if (formatData.ShiftType == ShiftType::Nothing) return FastReadFloatThrow(i, formatData.FloatPrecision); + else return ReadFloat(i, formatData.FloatPrecision, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + } + return FastReadFloatThrow(i, formatData.FloatPrecision); + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/Integer.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/Integer.h new file mode 100644 index 0000000..16700bf --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/Integer.h @@ -0,0 +1,208 @@ +#pragma once + +#include "FMTBufferIn.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + template + template + void FMTBufferIn::ReadInt(T& i, ShiftType st, ShiftSize shift, ShiftPrint sp) { + T res = 0; + + SkipShiftBeginSpace(st, sp, shift); + + bool sign = IsEqualToForward('-'); + if (sign) --shift; + + IsADigitThrow(); + + while (IsADigit()) { + res = res * 10 + (GetAndForward() - '0'); + --shift; + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + i = sign ? -res : res; + } + + template + template + void FMTBufferIn::ReadUInt(T& i, ShiftType st, ShiftSize shift, ShiftPrint sp) { + T res = 0; + + SkipShiftBeginSpace(st, sp, shift); + + IsADigitThrow(); + + while (IsADigit()) { + res = res * 10 + (GetAndForward() - '0'); + --shift; + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + i = res; + } + + template + template + void FMTBufferIn::ReadFloat(T& i, FloatPrecision floatPrecision, ShiftType st, ShiftSize shift, ShiftPrint sp) { + SkipShiftBeginSpace(st, sp, shift); + + bool sign = IsEqualToForward('-'); + if (sign) --shift; + + T res = 0; + + bool hasIntPart = false; + if (IsNotEqualTo('.')) + { + hasIntPart = IsADigit(); + if (hasIntPart == false) return; + while (IsADigit()) + { + res = res * 10 + (GetAndForward() - '0'); + --shift; + } + } + + sign ? i = -res : i = res; + if (IsEqualToForward('.') == false) return; + + if (floatPrecision.IsDefault() || floatPrecision == 0) + while (IsADigit() && IsEnd() == false) + { + ForwardNoCheck(); + --shift; + } + else + { + while (IsADigit() && floatPrecision > 0 && IsEnd() == false) + { + ForwardNoCheck(); + floatPrecision--; + --shift; + } + } + BackwardNoCheck(); + + T dec = (T)0; + while (IsADigit()) + { + dec += static_cast(GetAndBackwardNoCheck() - '0'); + dec /= 10; + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + sign ? i = -res - dec : i = res + dec; + } + + //---------------------------------------------// + //---------------------------------------------// + //---------------------------------------------// + + template + template + void FMTBufferIn::ReadIntAsBin(T& i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool trueValue) { + if (digitSize.IsDefault()) + digitSize = sizeof(T) * 8; + + shift -= digitSize; + if (trueValue) shift -= 2; + + SkipShiftBeginSpace(st, sp, shift); + + if (trueValue) { + Skip('0'); + Skip('b'); + } + + T res = 0; + + while (IsEqualTo('0', '1')) { + res = res << 1; + res += Get() - '0'; + Forward(); + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + i = res; + } + + template + template + void FMTBufferIn::ReadIntAsHex(T& i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool trueValue, [[maybe_unused]] Detail::PrintStyle printStyle) { + if (digitSize.IsDefault()) + digitSize = sizeof(T) * 2; + + shift -= digitSize; + if (trueValue) shift -= 2; + + SkipShiftBeginSpace(st, sp, shift); + + if (trueValue) { + Skip('0'); + Skip('x'); + } + + T res = 0; + + while (IsADigit() || (Get() >= 'A' && Get() <= 'F') || (Get() >= 'a' && Get() <= 'f')) { + res = res << 4; + if (IsADigit()) res += Get() - '0'; + else if (Get() >= 'A' && Get() <= 'F') res += Get() - 'A' + 10; + else if (Get() >= 'a' && Get() <= 'f') res += Get() - 'a' + 10; + Forward(); + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + i = res; + } + + template + template + void FMTBufferIn::ReadIntAsOct(T& i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool trueValue) { + if (digitSize.IsDefault()) + digitSize = std::ceil(static_cast(sizeof(T) * 8) / 3); + + shift -= digitSize; + if (trueValue) shift -= 2; + + SkipShiftBeginSpace(st, sp, shift); + + if (trueValue) { + Skip('0'); + Skip('o'); + } + + T res = 0; + + while (Get() >= '0' && Get() <= '8') { + res = res << 3; + res += Get() - '0'; + Forward(); + } + + SkipShiftEnd(st, sp, shift); + + if (shift > 0) throw FMTParseError(); + + i = res; + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/String.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/String.h new file mode 100644 index 0000000..1b5d8c6 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferIn/String.h @@ -0,0 +1,15 @@ +#pragma once + +#include "FMTBufferIn.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + inline void FMTBufferIn::ReadCharPtr([[maybe_unused]] const CharStr* str, [[maybe_unused]] std::size_t sizeContainer, [[maybe_unused]] std::size_t sizeToWrite, [[maybe_unused]] ShiftType st, [[maybe_unused]] ShiftSize shift, [[maybe_unused]] ShiftPrint sp) + { + // FIXME + // TODO + throw FMTImplError{}; + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FMTBufferOut.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FMTBufferOut.h new file mode 100644 index 0000000..5613ffe --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FMTBufferOut.h @@ -0,0 +1,205 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h" + +namespace ProjectCore::FMT::Detail +{ + template + class FMTBufferOut : public BasicBufferOut { + protected: + using Base = BasicBufferOut; + using Base::m_Buffer; + using Base::m_BufferEnd; + using Base::m_CurrentPos; + using Base::m_BufferOutManager; + + using Base::UPPER_HEX; + using Base::LOWER_HEX; + + public: + using typename Base::StringView; + + public: + using Base::GetBuffer; + using Base::GetBufferCurrentPos; + using Base::GetBufferEnd; + using Base::GetBufferSize; + using Base::GetBufferCurrentSize; + using Base::GetBufferRemainingSize; + using Base::SetBufferCurrentPos; + + using Base::ReloadBuffer; + using Base::SetBuffer; + + // using Base::SetBufferOutManager; + using Base::GetBufferOutManager; + + public: + using Base::CanMoveForward; + using Base::CanMoveForwardThrow; + using Base::CanMoveBackward; + using Base::CanMoveBackwardThrow; + + using Base::IsNotOutOfBound; + using Base::IsNotOutOfBoundThrow; + using Base::IsEnd; + using Base::IsEndThrow; + + using Base::Forward; + using Base::ForwardNoCheck; + using Base::ForwardNoThrow; + using Base::Backward; + using Base::BackwardNoCheck; + using Base::BackwardNoThrow; + using Base::Reserve; + + using Base::Get; + using Base::GetAndForward; + using Base::GetAndForwardNoCheck; + using Base::GetAndBackward; + using Base::GetAndBackwardNoCheck; + using Base::GetNext; + using Base::GetNextNoCheck; + using Base::GetPrev; + using Base::GetPrevNoCheck; + + public: + using Base::FastWriteInt; + using Base::FastWriteUInt; + using Base::FastWriteFloat; + + using Base::FastWriteCharPtr; + using Base::FastWriteCharPtrNSize; + using Base::FastWriteCharArray; + using Base::FastWriteCharBound; + using Base::FastWriteStringView; + using Base::FastWriteString; + + public: + using Base::BasicWriteType; + + protected: + using Base::GetNumberOfDigitDec; + + public: + using Base::AddSize; + + using Base::SetChar; + using Base::PushBack; + using Base::PushReverse; + using Base::PushBackNoCheck; + using Base::PushReverseNoCheck; + + using Base::PushBackEndChar; + using Base::AddSpaces; + + private: + std::size_t m_NoStride; + std::size_t m_Indent; + + public: + inline std::size_t GetNoStride() const noexcept { return m_NoStride; } + inline void AddNoStride(const std::size_t noStride) noexcept { m_NoStride += noStride; } + + inline std::size_t GetIndent() const noexcept { return m_Indent; } + inline void SetIndent(const std::size_t indent) noexcept { m_Indent = indent; } + inline void AddIndent(const std::size_t indent) noexcept { m_Indent += indent; } + inline void RemoveIndent(const std::size_t indent) noexcept { m_Indent -= indent; } + inline void SetIndent() noexcept { m_Indent = GetBufferCurrentSize() - GetNoStride(); } + + public: + FMTBufferOut(BasicBufferOutManager& BufferOutManager) + : Base(BufferOutManager) + , m_NoStride(0) + , m_Indent(0) + {} + + ~FMTBufferOut() override = default; + + public: + template void WriteInt (T i, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + template void WriteUInt (T i, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + template void WriteFloat (T i, FloatPrecision floatPrecision = FloatPrecision{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + + template void WriteIntAsBin (T i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool prefix = true); + template void WriteIntAsHex (T i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool prefix = true, Detail::PrintStyle uppercase = PrintStyle::Nothing); + template void WriteIntAsOct (T i, DigitSize digitSize = DigitSize{}, ShiftType st = ShiftType::Nothing, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}, bool prefix = true); + + public: + template void WriteIntFormatData (T i, const FormatData& formatData); + template void WriteUIntFormatData (T i, const FormatData& formatData); + template void WriteFloatFormatData (T i, const FormatData& formatData); + + public: + template + inline void WriteCharPtr(const CharStr* str, std::size_t size, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}); + + template inline void WriteCharPtrNSize(const CharStr* str, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { WriteStringView(std::basic_string_view(str), st, shift, sp); } + template inline void WriteCharArray(const CharStr(&str)[SIZE], ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { WriteCharPtr(str, str[SIZE - 1] == 0 ? SIZE - 1 : SIZE, st, shift, sp); } + template inline void WriteCharBound(const CharStr* begin, const CharStr* end, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { WriteCharPtr(begin, end - begin, st, shift, sp); } + template inline void WriteStringView(const std::basic_string_view& str, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { WriteCharPtr(str.data(), str.size(), st, shift, sp); } + template inline void WriteString(const std::basic_string& str, ShiftType st = ShiftType::Default, ShiftSize shift = ShiftSize{}, ShiftPrint sp = ShiftPrint{}) { WriteCharPtr(str.data(), str.size(), st, shift, sp); } + + public: + inline void NewLineIndent() { PushBack('\n'); PushBack(' ', m_Indent); } + inline void SetCharCheckIndent(const CharBuffer c) { SetChar(c); if (c == '\n') PushBack(' ', m_Indent); } + inline void PushBackCheckIndent(const CharBuffer c) { PushBack(c); if (c == '\n') PushBack(' ', m_Indent); } + + template + inline void WriteIndentCharPtr(const CharStr* str, std::size_t size); + + template inline void WriteIndentCharPtrNSize(const CharStr* str) { WriteIndentStringView(std::basic_string_view(str)); } + template inline void WriteIndentCharArray(const CharStr(&str)[SIZE]) { WriteIndentCharPtr(str, str[SIZE - 1] == 0 ? SIZE - 1 : SIZE); } + template inline void WriteIndentCharBound(const CharStr* begin, const CharStr* end) { WriteIndentCharPtr(begin, end - begin); } + template inline void WriteIndentStringView(const std::basic_string_view& str) { WriteIndentCharPtr(str.data(), str.size()); } + template inline void WriteIndentString(const std::basic_string& str) { WriteIndentCharPtr(str.data(), str.size()); } + + public: + // Shift + template + inline void PrintShiftCenterBegin(const Detail::ShiftType st, const Detail::ShiftPrint sp, T& shift) { + if(st == Detail::ShiftType::CenterRight || st == Detail::ShiftType::CenterLeft) + { + DataType shift_ = shift / 2; + if (st == Detail::ShiftType::CenterLeft) + shift_ = (shift + 1) / 2; + PushBack(sp.Before, shift - shift_); + shift = shift_; + } + } + + template + inline void PrintShiftCenterEnd(const Detail::ShiftType st, const Detail::ShiftPrint sp, const T shift) { + if (st == Detail::ShiftType::CenterRight || st == Detail::ShiftType::CenterLeft) + PushBack(sp.After, shift); + } + + template + inline void PrintShiftRightAll(const Detail::ShiftType st, const Detail::ShiftPrint sp, const T shift) { + if (st == Detail::ShiftType::Right) + PushBack(sp.Before, shift); + } + + template + inline void PrintShiftLeftAll(const Detail::ShiftType st, const Detail::ShiftPrint sp, const T shift) { + if (st == Detail::ShiftType::Left) + PushBack(sp.After, shift); + } + + template + inline void PrintShiftBegin(const Detail::ShiftType st, const Detail::ShiftPrint sp, T& shift) { + PrintShiftCenterBegin(st, sp, shift); + PrintShiftRightAll(st, sp, shift); + } + + template + inline void PrintShiftEnd(const Detail::ShiftType st, const Detail::ShiftPrint sp, T& shift) { + PrintShiftLeftAll(st, sp, shift); + PrintShiftCenterEnd(st, sp, shift); + } + }; +} + +#include "Integer.h" +#include "FromFormatData.h" +#include "String.h" diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FromFormatData.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FromFormatData.h new file mode 100644 index 0000000..c038b2c --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/FromFormatData.h @@ -0,0 +1,58 @@ +#pragma once + +#include "Integer.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + void FMTBufferOut::WriteIntFormatData(T i, const FormatData& formatData) { + if (formatData.HasSpec) + { + switch (formatData.IntPrint) { + case ValueIntPrint::Dec: + if (formatData.ShiftType == ShiftType::Nothing) return FastWriteInt(i); + else return WriteInt(i, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + case ValueIntPrint::Bin: + return WriteIntAsBin(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + case ValueIntPrint::Hex: + return WriteIntAsHex(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue, formatData.PrintStyle); + case ValueIntPrint::Oct: + return WriteIntAsOct(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + } + } + return FastWriteInt(i); + } + + template + template + void FMTBufferOut::WriteUIntFormatData(T i, const FormatData& formatData) { + if (formatData.HasSpec) + { + switch (formatData.IntPrint) { + case ValueIntPrint::Dec: + if (formatData.ShiftType == ShiftType::Nothing) return FastWriteUInt(i); + else return WriteUInt(i, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + case ValueIntPrint::Bin: + return WriteIntAsBin(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + case ValueIntPrint::Hex: + return WriteIntAsHex(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue, formatData.PrintStyle); + case ValueIntPrint::Oct: + return WriteIntAsOct(i, formatData.DigitSize, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint, formatData.TrueValue); + } + } + return FastWriteUInt(i); + } + + template + template + void FMTBufferOut::WriteFloatFormatData(T i, const FormatData& formatData) { + if (formatData.HasSpec) + { + if (formatData.ShiftType != ShiftType::Nothing) + return WriteFloat(i, formatData.FloatPrecision, formatData.ShiftType, formatData.ShiftSize, formatData.ShiftPrint); + } + + return FastWriteFloat(i, formatData.FloatPrecision); + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/Integer.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/Integer.h new file mode 100644 index 0000000..7218876 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/Integer.h @@ -0,0 +1,244 @@ +#pragma once + +#include "FMTBufferOut.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + template + template + void FMTBufferOut::WriteInt(T i, ShiftType st, ShiftSize shift, ShiftPrint sp) { + sp.ValidateForNumber(); + + DataType nbDigit = GetNumberOfDigitDec(i); + + shift -= nbDigit; + if (i < 0) --shift; + + if (shift <= 0) + return FastWriteInt(i); + + if (!sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + if (i < 0) { PushBack('-'); i = -i; } + if (sp.BeforeIsADigit()) PrintShiftRightAll(st, sp, shift); + + if (i == 0) PushBack('0'); + else + { + Reserve(nbDigit); + DataType nbDigit_ = nbDigit; + while (nbDigit_ > 0) { PushReverseNoCheck(i % 10 + '0'); i /= 10; nbDigit_--; } + Forward(nbDigit + 1); + } + + PrintShiftEnd(st, sp, shift); + } + + template + template + void FMTBufferOut::WriteUInt(T i, ShiftType st, ShiftSize shift, ShiftPrint sp) { + sp.ValidateForNumber(); + + DataType nbDigit = GetNumberOfDigitDec(i); + shift -= nbDigit; + + if (shift <= 0) + return FastWriteUInt(i); + + PrintShiftBegin(st, sp, shift); + + if (i == 0) PushBack('0'); + else + { + Reserve(nbDigit); + DataType nbDigit_ = nbDigit; + while (nbDigit_ > 0) { PushReverseNoCheck(i % 10 + '0'); i /= 10; nbDigit_--; } + Forward(nbDigit + 1); + } + + PrintShiftEnd(st, sp, shift); + } + + template + template + void FMTBufferOut::WriteFloat(T i, FloatPrecision nbDecimal, ShiftType st, ShiftSize shift, ShiftPrint sp) { + sp.ValidateForNumber(); + + DataType nbDigit = GetNumberOfDigitDec(std::trunc(i)); + nbDecimal.SetToBasicSizeIfDefault(); + + shift -= nbDigit + nbDecimal + 1; + if (i < 0) --shift; + + if (shift <= 0) return FastWriteFloat(i, nbDecimal); + + if (!sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + if (i < 0) { PushBack('-'); i = -i; } + if (sp.BeforeIsADigit()) PrintShiftRightAll(st, sp, shift); + + T k = std::trunc(i); + if (k == 0) PushBack('0'); + else + { + Reserve(nbDigit); + DataType nbDigit_ = nbDigit; + while (nbDigit_ > 0) + { + PushReverseNoCheck(char(std::fmod(i, 10)) + '0'); + k /= 10; + nbDigit_--; + } + Forward(nbDigit + 1); + } + + PushBack('.'); + i -= k; + while (nbDecimal-- != 0) + { + T decimal = std::trunc(i *= 10); + PushBack((char)decimal + '0'); + i -= decimal; + } + + PrintShiftEnd(st, sp, shift); + } + + + //---------------------------------------------// + //---------------------------------------------// + //---------------------------------------------// + + template + template + void FMTBufferOut::WriteIntAsBin(T i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool prefix) { + sp.ValidateForNumber(); + + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(sizeof(T) * 8); + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if (cpyI & 1) lastPosWithData = k; + cpyI = cpyI >> 1; + } + digitSize -= lastPosWithData; + } + + shift -= digitSize; + if (prefix) shift -= 2; + if (shift < 0) shift = 0; + + if (!sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + if (prefix) { + PushBack('0'); + PushBack('b'); + } + if (sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + + // Print value + Reserve(digitSize); + DataType k = digitSize + 1; + while (--k != 0) { + if (i & 1) PushReverseNoCheck('1'); + else PushReverseNoCheck('0'); + i = i >> 1; + } + Forward(digitSize + 1); + + PrintShiftEnd(st, sp, shift); + } + + template + template + void FMTBufferOut::WriteIntAsHex(T i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool prefix, Detail::PrintStyle uppercase) { + sp.ValidateForNumber(); + + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(sizeof(T) * 2); + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if ((cpyI & 0b1111) != 0) lastPosWithData = k; + cpyI = cpyI >> 4; + } + digitSize -= lastPosWithData; + } + + shift -= digitSize; + if (prefix) shift -= 2; + if (shift < 0) shift = 0; + + if (!sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + if (prefix) { + PushBack('0'); + PushBack('x'); + } + if (sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + + // Print value + Reserve(digitSize); + DataType k = digitSize + 1; + if (uppercase == PrintStyle::LowerCase) + while (--k != 0) { PushReverseNoCheck(LOWER_HEX[i & 0b1111]); i = i >> 4; } + else + while (--k != 0) { PushReverseNoCheck(UPPER_HEX[i & 0b1111]); i = i >> 4; } + Forward(digitSize + 1); + + PrintShiftEnd(st, sp, shift); + } + + template + template + void FMTBufferOut::WriteIntAsOct(T i, DigitSize digitSize, ShiftType st, ShiftSize shift, ShiftPrint sp, bool prefix) { + sp.ValidateForNumber(); + + bool removeLeading0 = digitSize.IsDefault(); + + if (digitSize.Value == DigitSize::MAX_DIGIT_SIZE || digitSize.IsDefault()) + digitSize = static_cast(std::ceil(static_cast(sizeof(T) * 8) / 3)); + + if (removeLeading0) + { + DataType lastPosWithData = 0; + DataType k = digitSize + 1; + T cpyI = i; + while (--k != 0) { + if ((cpyI & 0b111) != 0) lastPosWithData = k; + cpyI = cpyI >> 4; + } + digitSize -= lastPosWithData; + } + + shift -= digitSize; + if (prefix) shift -= 2; + if (shift < 0) shift = 0; + + if (!sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + if (prefix) { + PushBack('0'); + PushBack('o'); + } + if (sp.BeforeIsADigit()) PrintShiftBegin(st, sp, shift); + + // Print value + Reserve(digitSize); + DataType k = digitSize + 1; + while (--k != 0) { PushReverseNoCheck((i & 0b111) + '0'); i = i >> 3; } + Forward(digitSize + 1); + + PrintShiftEnd(st, sp, shift); + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/String.h b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/String.h new file mode 100644 index 0000000..3817654 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTBufferOut/String.h @@ -0,0 +1,52 @@ +#pragma once + +#include "FMTBufferOut.h" + +namespace ProjectCore::FMT::Detail +{ + template + template + inline void FMTBufferOut::WriteCharPtr(const CharStr* str, std::size_t size, ShiftType st, ShiftSize shift, ShiftPrint sp) + { + if (CanMoveForward(std::max(static_cast(shift.Value), size)) == false) + return WriteCharPtr(str, GetBufferRemainingSize(), st, shift, sp); + + if (static_cast(shift) > size) + { + shift -= static_cast(size); + + PrintShiftBegin(st, sp, shift); + + FastWriteCharPtr(str, size); + + PrintShiftEnd(st, sp, shift); + } + else + { + FastWriteCharPtr(str, size); + } + } + + template + template + inline void FMTBufferOut::WriteIndentCharPtr(const CharStr* str, std::size_t size) + { + while (size > 0) + { + const CharStr* const begin = str; + while (size > 0 && *str != '\n') + { + ++str, --size; + } + const CharStr* const end = str; + + FastWriteCharBound(begin, end); + + if (size > 0 && *str == '\n') + { + NewLineIndent(); + ++str; --size; + } + } + } +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/FMTFormatBuffer/FMTFormatBuffer.h b/src/ProjectCore/FMT/Detail/Buffer/FMTFormatBuffer/FMTFormatBuffer.h new file mode 100644 index 0000000..eb2590f --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/FMTFormatBuffer/FMTFormatBuffer.h @@ -0,0 +1,205 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/FMTBufferIn/FMTBufferIn.h" + +namespace ProjectCore::FMT::Detail +{ + template + class FMTFormatBuffer : public FMTBufferIn { + + protected: + using Base = FMTBufferIn; + using Base::m_Buffer; + using Base::m_BufferEnd; + using Base::m_CurrentPos; + + public: + using typename Base::StringView; + + public: + using Base::GetBuffer; + using Base::GetBufferCurrentPos; + using Base::GetBufferEnd; + using Base::GetBufferSize; + using Base::GetBufferCurrentSize; + using Base::GetBufferRemainingSize; + using Base::SetBufferCurrentPos; + + using Base::ReloadBuffer; + using Base::SetBuffer; + + public: + using Base::CanMoveForward; + using Base::CanMoveForwardThrow; + using Base::CanMoveBackward; + using Base::CanMoveBackwardThrow; + using Base::IsNotOutOfBound; + using Base::IsNotOutOfBoundThrow; + using Base::IsEnd; + using Base::IsEndThrow; + + using Base::Forward; + using Base::ForwardNoCheck; + using Base::ForwardNoThrow; + using Base::Backward; + using Base::BackwardNoCheck; + using Base::BackwardNoThrow; + using Base::Reserve; + + using Base::Get; + using Base::GetAndForward; + using Base::GetAndForwardNoCheck; + using Base::GetAndBackward; + using Base::GetAndBackwardNoCheck; + using Base::GetNext; + using Base::GetNextNoCheck; + using Base::GetPrev; + using Base::GetPrevNoCheck; + + public: + using Base::FastReadIntThrow; + using Base::FastReadUIntThrow; + using Base::FastReadFloatThrow; + + using Base::ReadInt; + using Base::ReadUInt; + using Base::ReadFloat; + using Base::ReadIntAsBin; + using Base::ReadIntAsHex; + using Base::ReadIntAsOct; + + using Base::ReadIntFormatData; + using Base::ReadUIntFormatData; + using Base::ReadFloatFormatData; + + using Base::ReadCharPtr; + using Base::ReadCharArray; + using Base::ReadCharBound; + + using Base::BasicReadType; + + public: + using Base::IsEqualTo; + using Base::IsNotEqualTo; + using Base::IsEqualToForward; + using Base::IsNotEqualForward; + using Base::IsEqualToThrow; + using Base::IsNotEqualToThrow; + using Base::IsEqualToForwardThrow; + using Base::Skip; + using Base::IsNotEqualForwardThrow; + + using Base::NextIsEqualTo; + using Base::NextIsNotEqualTo; + using Base::NextIsEqualToForward; + using Base::NextIsNotEqualForward; + using Base::NextIsEqualToThrow; + using Base::NextIsNotEqualToThrow; + using Base::NextIsEqualToForwardThrow; + using Base::NextIsNotEqualForwardThrow; + + using Base::PrevIsEqualTo; + using Base::PrevIsNotEqualTo; + using Base::PrevIsEqualToThrow; + using Base::PrevIsNotEqualToThrow; + + using Base::IsLowerCase; + using Base::IsUpperCase; + using Base::IsADigit; + using Base::IsLowerCaseForward; + using Base::IsUpperCaseForward; + using Base::IsADigitForward; + using Base::IsLowerCaseThrow; + using Base::IsUpperCaseThrow; + using Base::IsADigitThrow; + using Base::IsLowerCaseForwardThrow; + using Base::IsUpperCaseForwardThrow; + using Base::IsADigitForwardThrow; + + + using Base::IsSameSeq; + using Base::IsSameSeqForward; + using Base::IsSameSeqThrow; + using Base::IsSameSeqForwardThrow; + using Base::IsSame; + using Base::IsSameForward; + using Base::IsSameThrow; + using Base::IsSameForwardThrow; + + using Base::GetWordFromList; + + using Base::Ignore; + using Base::IgnoreAll; + using Base::GoTo; + using Base::GoToForward; + + using Base::IsBlank; + using Base::IsBlankForward; + using Base::IsBlankThrow; + using Base::IsBlankForwardThrow; + + using Base::IgnoreBlank; + using Base::IgnoreSpace; + using Base::IgnoreAllBlanks; + using Base::IgnoreAllSpaces; + + + protected: + using Base::SkipShiftBeginSpace; + using Base::SkipShiftEnd; + + public: + FMTFormatBuffer() : Base() {} + FMTFormatBuffer(const BufferInProperties& properties) : Base(properties) {} + + FMTFormatBuffer(const CharFormat* const buffer, const std::size_t bufferSize) + : Base(buffer, bufferSize) + {} + + ~FMTFormatBuffer() noexcept override = default; + + public: + // Format commands in parameter (add check to '}' to avoid skip the end of the format specifier) + template inline void ParamGoTo(const CharToTest ...ele) { GoTo(ele..., '}'); } + template inline void ParamGoToForward(const CharToTest ...ele) { GoToForward(ele..., '}'); } + + template inline void GoToNextParamOr(const CharToTest ...ele) { GoTo(ele..., '{'); } + template inline void GoToNextParamOrForward(const CharToTest ...ele) { GoToForward(ele..., '{'); } + + inline bool IsBeginOfParameter() { return IsEqualTo('{'); } + inline void GoToBeginOfParameter() { while (IsNotEqualTo('{') && CanMoveForward()) ForwardNoCheck(); } + inline void GoAfterBeginOfParameter() { while (IsNotEqualTo('{') && CanMoveForward()) ForwardNoCheck(); Forward(); } + + inline bool IsEndOfParameter() { return IsEqualTo('}'); } + inline void GoToEndOfParameter() { while (IsNotEqualTo('}') && CanMoveForward()) ForwardNoCheck(); } + inline void GoOutOfParameter() { while (IsNotEqualTo('}') && CanMoveForward()) ForwardNoCheck(); Forward(); } + + public: + // TODO Better way || way to verbous + template + StringView ParamGoToAndGetStr(const CharToTest ...args) + { + const CharFormat* begin = GetBufferCurrentPos(); + ParamGoTo(args...); + const CharFormat* end = GetBufferCurrentPos(); + return StringView(begin, end); + } + + template + StringView ParamGoToForwardAndGetStr(const CharToTest ...args) + { + const CharFormat* begin = GetBufferCurrentPos(); + ParamGoToForward(args...); + const CharFormat* end = GetBufferCurrentPos(); + return StringView(begin, end); + } + + public: + template bool NextIsANamedArgs(const std::basic_string_view& sv) { + const CharToTest* const prevSubFormat = m_CurrentPos; + if (IsSameForward(sv) && (IsEqualTo(':') || IsEqualTo('}'))) return true; + m_CurrentPos = prevSubFormat; + return false; + } + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/Utils/BufferUtils.h b/src/ProjectCore/FMT/Detail/Buffer/Utils/BufferUtils.h new file mode 100644 index 0000000..ac42f42 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/Utils/BufferUtils.h @@ -0,0 +1,73 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h" +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h" + +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/StaticBufferOutManager.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferOutManager/GivenBufferOutManager.h" + +namespace ProjectCore::FMT +{ + template + class BufferUtils + { + public: + using BufferInType = Detail::BasicBufferIn; + using BufferOutType = Detail::BasicBufferOut; + + public: + static void ParseEscapedQuotedString(BufferInType& buffer, BufferOutType& stringOut) + { + buffer.Skip('"'); + while(buffer.IsEnd() == false) + { + const CharBuffer* beginString = buffer.GetBufferCurrentPos(); + buffer.GoTo('"', '\\'); + const CharBuffer* endString = buffer.GetBufferCurrentPos(); + stringOut.FastWriteCharBound(beginString, endString); + + if (buffer.IsEqualTo('"')) + break; + + buffer.Skip('\\'); + switch (buffer.Get()) + { + // TODO : Do all others escape char + case '"': stringOut.PushBack('"'); break; + case 't': stringOut.PushBack('\t'); break; + case 'r': stringOut.PushBack('\r'); break; + case 'n': stringOut.PushBack('\n'); break; + default: break; + } + } + buffer.Skip('"'); + } + + static void FormatEscapedQuotedString(BufferOutType& buffer, BufferInType& stringIn) + { + buffer.PushBack('"'); + while(stringIn.IsEnd() == false) + { + const CharBuffer* beginString = stringIn.GetBufferCurrentPos(); + stringIn.GoTo('\\'); + const CharBuffer* endString = stringIn.GetBufferCurrentPos(); + buffer.FastWriteCharBound(beginString, endString); + + if (stringIn.IsEnd()) break; + + stringIn.Skip('\\'); + switch (stringIn.Get()) + { + // TODO : Do all others escape char + case '"': buffer.PushBack('"'); break; + case 't': buffer.PushBack('\t'); break; + case 'r': buffer.PushBack('\r'); break; + case 'n': buffer.PushBack('\n'); break; + default: break; + } + } + buffer.PushBack('"'); + } + }; +} diff --git a/src/ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h b/src/ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h new file mode 100644 index 0000000..75d3b1d --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Buffer/Utils/PatternMatching/Glob/Glob.h @@ -0,0 +1,108 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h" + +namespace ProjectCore::FMT::Detail +{ + template + class Globber + { + public: + using BufferInType = BasicBufferIn; + using PatternType = BasicBufferIn; + + public: + enum class PatternMatchType + { + MatchBiggest, + MatchSmallest + }; + + private: + static const CharBuffer* BufferInExecGlob_(BufferInType bufferIn, PatternType glob) + { + if (glob.IsEnd()) + return bufferIn.GetBufferCurrentPos(); + + if (bufferIn.IsEnd()) + return nullptr; + + if (glob.IsEqualTo('?')) + { + glob.Forward(); + bufferIn.Forward(); + return BufferInExecGlob_(bufferIn, glob); + } + else if (glob.IsEqualTo('*')) + { + glob.Forward(); + const CharBuffer* further = BufferInExecGlob_(bufferIn, glob); + while (bufferIn.CanMoveForward()) + { + bufferIn.Forward(); + const CharBuffer* last = BufferInExecGlob_(bufferIn, glob); + if (last > further || further == nullptr) + further = last; + } + return further; + } + else if (glob.IsEqualTo('[')) + { + glob.Forward(); + const CharPattern* begin = glob.GetBufferCurrentPos(); + glob.GoToForward(']'); + const CharPattern* end = glob.GetBufferCurrentPos(); + + PatternType charSet(begin, end); + + bool is_inverted = glob.IsEqualToForward('!'); + CharBuffer toMatch = bufferIn.GetAndForward(); + bool found = false; + + while (found == false && charSet.CanMoveForward()) + { + if (charSet.IsEqualTo(toMatch)) + { + found = true; + break; + } + + if (charSet.IsEqualTo('-')) + { + CharPattern beginSubSet = charSet.GetPrev(); + CharPattern endSubSet = charSet.GetNext(); + if (toMatch >= beginSubSet && toMatch <= endSubSet) + { + found = true; + break; + } + } + + charSet.Forward(); + } + + if (found && is_inverted == false) + return BufferInExecGlob_(bufferIn, glob); + else if (found == false && is_inverted == true) + return BufferInExecGlob_(bufferIn, glob); + return nullptr; + } + + if (bufferIn.Get() == glob.Get()) + { + glob.Forward(); + bufferIn.Forward(); + return BufferInExecGlob_(bufferIn, glob); + } + return nullptr; + } + + public: + static void BufferInExecGlob(BufferInType& bufferIn, PatternType glob, [[maybe_unused]] PatternMatchType patternMatchtype = PatternMatchType::MatchBiggest) + { + const CharBuffer* furtherPointMatched = BufferInExecGlob_(bufferIn, glob); + if (furtherPointMatched != nullptr) + bufferIn.SetBufferCurrentPos(furtherPointMatched); + } + }; +} diff --git a/src/ProjectCore/FMT/Detail/Detail.h b/src/ProjectCore/FMT/Detail/Detail.h new file mode 100644 index 0000000..7dd9e48 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Detail.h @@ -0,0 +1,45 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +#include "Types/Types.h" +#include "Types/TypesInfo.h" +#include "Types/TypesTraits.h" + +#include "Exception.h" +#include "Specifiers.h" +#include "IndentHandlers.h" +#include "UtilsContextsFunctions.h" + +#include "TextProperties/TextProperties.h" + +#define UNKOWN_TYPE_MESSAGE + +// TODO : +// +// Check for escape char +// +// Macro PackSave ; PackSave (foreshadowing for constexpr) +// +// TOKENIZER bufferIn +// +// GLOBBER +// +// REGEX +// {I:REGEX} +// {:regex=REGEX} (string / char array) +// {} +// +// End writing all writer and reader (string / char pt) +// + +namespace ProjectCore::FMT::Context +{ + template + class BasicFormatterContext; + + struct ParserContextError; + + template + class BasicParserContext; +} diff --git a/src/ProjectCore/FMT/Detail/Exception.h b/src/ProjectCore/FMT/Detail/Exception.h new file mode 100644 index 0000000..5068dbc --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Exception.h @@ -0,0 +1,28 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + class FMTException : public std::exception {}; + class FMTError : public FMTException { public: const char* what() const noexcept override { return "FMTError"; } }; + class FMTUtilityException : public FMTException { public: const char* what() const noexcept override { return "FMTUtilityException"; } }; + + class FMTBufferError : public FMTError { public: const char* what() const noexcept override { return "FMTBufferError"; } }; + class FMTBufferFull : public FMTBufferError { public: const char* what() const noexcept override { return "FMTBufferFull"; } }; + class FMTBufferLock : public FMTBufferError { public: const char* what() const noexcept override { return "FMTBufferLock"; } }; + class FMTBufferEnd : public FMTBufferError { public: const char* what() const noexcept override { return "FMTBufferEnd"; } }; + + class FMTIndexError : public FMTError { public: const char* what() const noexcept override { return "FMTIndexError"; } }; + class FMTBufferWrongIndex : public FMTIndexError { public: const char* what() const noexcept override { return "FMTBufferWrongIndex"; } }; + class FMTBufferIndexOutOfRange : public FMTIndexError { public: const char* what() const noexcept override { return "FMTBufferIndexOutOfRange"; } }; + + class FMTParseError : public FMTError { public: const char* what() const noexcept override { return "FMTParseError"; } }; + class FMTGivenTypeError : public FMTParseError { public: const char* what() const noexcept override { return "FMTGivenTypeError"; } }; + + class FMTImplError : public FMTError { public: const char* what() const noexcept override { return "FMTImplError"; } }; + class FMTShouldNotEndHere : public FMTImplError { public: const char* what() const noexcept override { return "FMTShouldNotEndHere"; } }; + class FMTNotImplYet : public FMTImplError { public: const char* what() const noexcept override { return "FMTNotImplYet"; } }; +} diff --git a/src/ProjectCore/FMT/Detail/FormatterHandler/FormatterHandler.h b/src/ProjectCore/FMT/Detail/FormatterHandler/FormatterHandler.h new file mode 100644 index 0000000..5e7097a --- /dev/null +++ b/src/ProjectCore/FMT/Detail/FormatterHandler/FormatterHandler.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" +#include + +namespace ProjectCore::FMT::Detail +{ + class FormatterHandler + { + public: + static void SetBeginTime() { sm_TimeShift = std::chrono::high_resolution_clock::now(); } + static void SetHoursShift(const std::chrono::hours& hoursShift) { sm_HoursShift = hoursShift; } + static const std::chrono::time_point& GetTimeShift() { return sm_TimeShift; } + static const std::chrono::hours& GetHoursShift() { return sm_HoursShift; } + + private: + FormatterHandler() = default; + ~FormatterHandler() = default; + FormatterHandler(const FormatterHandler& other) = delete; + FormatterHandler(FormatterHandler&& other) = delete; + + private: + static inline std::chrono::time_point sm_TimeShift; + static inline std::chrono::hours sm_HoursShift{}; + }; +} + +#define PROJECTCORE_FORMATTER_TIME_BEGIN() ProjectCore::FMT::Detail::FormatterHandler::SetBeginTime() +#define PROJECTCORE_FORMATTER_SET_TIME_GTM(i) ProjectCore::FMT::Detail::FormatterHandler::SetHoursShift(std::chrono::hours(i)) diff --git a/src/ProjectCore/FMT/Detail/Forwarders.h b/src/ProjectCore/FMT/Detail/Forwarders.h new file mode 100644 index 0000000..8150049 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Forwarders.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace ProjectCore::FMT::Detail +{ + template struct ForwardAsInt; + template struct ForwardAsUInt; + template struct ForwardAsFloat; + template struct ForwardAsChar {}; + template struct ForwardAsCharArray {}; + template struct ForwardAsCharPointer {}; +} diff --git a/src/ProjectCore/FMT/Detail/IndentHandlers.h b/src/ProjectCore/FMT/Detail/IndentHandlers.h new file mode 100644 index 0000000..6edb06d --- /dev/null +++ b/src/ProjectCore/FMT/Detail/IndentHandlers.h @@ -0,0 +1,112 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Detail.h" + +namespace ProjectCore::FMT::Detail +{ + template + struct NoStrideFunction { + inline explicit NoStrideFunction(BufferContext& buffer) + : Buffer(buffer) + , SizeBuffer(Buffer.GetBufferCurrentSize()) {} + + ~NoStrideFunction() { + Buffer.AddNoStride(Buffer.GetBufferCurrentSize() - SizeBuffer); + } + + BufferContext& Buffer; + std::size_t SizeBuffer; + }; + + template + struct IndentInfo + { + inline IndentInfo() + : Restore(true) + , AddIndent(0) + {} + + inline explicit IndentInfo(const std::basic_string_view& txt) + : Restore(false) + , AddIndent(txt.size()) + { + for (std::size_t k = 0; k < txt.size(); ++k) + { + if (txt[k] == '\n') + { + Restore = true; + AddIndent = txt.size() - k - 1; + } + } + } + + bool Restore; + std::size_t AddIndent; + }; + + template + class RestoreIndentFunction + { + inline explicit RestoreIndentFunction(FormatterContext& context) + : m_Context(context) + , m_OldIndent(context.GetIndent()) + , m_IndentInfo() + , m_AddIndentEnd(false) + {} + + template + inline RestoreIndentFunction(FormatterContext& context, const std::basic_string_view& txt, bool addIndentEnd = true) + : m_Context(context) + , m_OldIndent(context.BufferOut().GetIndent()) + , m_IndentInfo(txt) + , m_AddIndentEnd(addIndentEnd) + {} + + ~RestoreIndentFunction() { + if (m_IndentInfo.Restore) + m_Context.BufferOut().SetIndent(m_OldIndent); + if (m_AddIndentEnd) + m_Context.BufferOut().AddIndent(m_IndentInfo.AddIndent); + } + + private: + FormatterContext& m_Context; + std::size_t m_OldIndent; + IndentInfo m_IndentInfo; + bool m_AddIndentEnd; + }; + + template + struct IndentFunctionData + { + inline explicit IndentFunctionData(FormatterContext& context) + : Context(context) + , OldNoStride(context.BufferOut().GetNoStride()) + , OldBufferSize(context.BufferOut().GetBufferCurrentSize()) + {} + + inline std::size_t GetIndent() + { + return (Context.BufferOut().GetBufferCurrentSize() - OldBufferSize) - (Context.BufferOut().GetNoStride() - OldNoStride); + } + + FormatterContext& Context; + std::size_t OldNoStride; + std::size_t OldBufferSize; + }; + + template + class IndentFunction + { + explicit inline IndentFunction(FormatterContext& context) + : m_IndentFunctionData(context) + {} + + ~IndentFunction() { + m_IndentFunctionData.Context.AddIndent(m_IndentFunctionData.GetIndent()); + } + + private: + IndentFunctionData m_IndentFunctionData; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Specifiers.h b/src/ProjectCore/FMT/Detail/Specifiers.h new file mode 100644 index 0000000..f5944a2 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Specifiers.h @@ -0,0 +1,379 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" +#include "Types/Types.h" + +#include +#include + +namespace ProjectCore::FMT::Detail +{ + enum class ValueIntPrint : DataType + { + Dec, + Bin, + Hex, + Oct, + Default = Dec + }; + + /* + enum class IndentStyle : DataType + { + None, + Indent + }; + */ + + enum class ShiftType : DataType + { + Nothing, + Right, + Left, + CenterRight, + CenterLeft, + Default = Nothing + }; + + enum class PrintStyle : DataType + { + Nothing, + UpperCase, + LowerCase, + Default = Nothing + }; + + struct ShiftPrint { + public: + constexpr ShiftPrint() + : Before(' ') + , After(' ') + {} + + constexpr ShiftPrint(char c) + : Before(c) + , After(c) + {} + + constexpr ShiftPrint(char before, char after) + : Before(before) + , After(after) + {} + + public: + char Before; + char After; + + public: + constexpr bool BeforeIsADigit() const { return Before >= '0' && Before <= '9'; } + + constexpr void ValidateForNumber() { if (After >= '0' && After <= '9') After = ' '; } + }; + + static constexpr ShiftPrint ShiftPrint_Space = ShiftPrint(' '); + static constexpr ShiftPrint ShiftPrint_Zeros = ShiftPrint('0', ' '); + static constexpr ShiftPrint ShiftPrint_Chevron = ShiftPrint('>', '<'); + + // No need of virtual destructor since DigitSize is purely a renaming of BasicCustomDataType + struct DigitSize : public BasicCustomDataType + { + public: + static constexpr DataType MAX_DIGIT_SIZE = std::numeric_limits::max(); + + public: + inline constexpr DigitSize(const DataType value = DEFAULT) + : BasicCustomDataType(value) + {} + + public: + using Base = BasicCustomDataType; + using Base::operator+; + using Base::operator-; + using Base::operator++; + using Base::operator--; + + using Base::operator=; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + }; + + // No need of virtual destructor since ShiftSize is purely a renaming of BasicCustomDataType + struct ShiftSize : public BasicCustomDataType + { + public: + inline constexpr ShiftSize(const DataType value = DEFAULT) + : BasicCustomDataType(value) + {} + + public: + using Base = BasicCustomDataType; + using Base::operator+; + using Base::operator-; + using Base::operator++; + using Base::operator--; + + using Base::operator=; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + }; + + // No need of virtual destructor since FloatPrecision is purely a renaming of BasicCustomDataType + struct FloatPrecision : public BasicCustomDataType + { + public: + static constexpr DataType BASIC_DECIMAL_SIZE = 4; + + public: + inline constexpr FloatPrecision(const DataType value = DEFAULT) + : BasicCustomDataType(value) + {} + + inline constexpr void SetToBasicSizeIfDefault() { if (IsDefault()) Value = BASIC_DECIMAL_SIZE; } + + public: + using Base = BasicCustomDataType; + using Base::operator+; + using Base::operator-; + using Base::operator++; + using Base::operator--; + + using Base::operator=; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + }; + +} + +namespace ProjectCore::FMT::Detail +{ + template + struct FormatSpecifier { + FormatSpecifier() + : Name(nullptr, 0) + , ValueAsText(nullptr, 0) + , ValueAsNumber(0) + , ValueHasText(false) + , ValueHasNumber(false) + {} + + FormatSpecifier(const std::basic_string_view& name) + : Name(name) + , ValueAsText(nullptr, 0) + , ValueAsNumber(0) + , ValueHasText(false) + , ValueHasNumber(false) + {} + + FormatSpecifier(const std::basic_string_view& name, const std::basic_string_view& value) + : Name(name) + , ValueAsText(value) + , ValueAsNumber(0) + , ValueHasText(true) + , ValueHasNumber(false) + {} + + FormatSpecifier(const std::basic_string_view& name, const Detail::DataType value) + : Name(name) + , ValueAsText(nullptr, 0) + , ValueAsNumber(value) + , ValueHasText(false) + , ValueHasNumber(true) + {} + + FormatSpecifier(const std::basic_string_view& name, const Detail::DataType valueAsNumber, const std::basic_string_view& valueAsText) + : Name(name) + , ValueAsText(valueAsText) + , ValueAsNumber(valueAsNumber) + , ValueHasText(true) + , ValueHasNumber(true) + {} + + FormatSpecifier(const std::basic_string_view& name, const std::basic_string_view& valueAsText, const Detail::DataType valueAsNumber) + : Name(name) + , ValueAsText(valueAsText) + , ValueAsNumber(valueAsNumber) + , ValueHasText(true) + , ValueHasNumber(true) + {} + + static inline constexpr Detail::DataType SpecifierAsNumberNotSpecified = Detail::FORMAT_DATA_NOT_SPECIFIED; + static inline constexpr std::basic_string_view SpecifierAsTextNotSpecified = std::basic_string_view(""); + + std::basic_string_view Name; + std::basic_string_view ValueAsText; + Detail::DataType ValueAsNumber; + bool ValueHasText; + bool ValueHasNumber; + }; + + template + struct FormatData { + public: + using FormatSpecifierType = FormatSpecifier; + + public: + bool IsInit = false; + bool HasSpec = false; + + bool KeepNewStyle = false; // W + + bool TrueValue = false; // = + bool Safe = false; // Safe + + Detail::ValueIntPrint IntPrint = Detail::ValueIntPrint::Default; // B - X - O - D + Detail::DigitSize DigitSize = Detail::DigitSize{}; // B? - X? - O? - D? + Detail::FloatPrecision FloatPrecision = Detail::FloatPrecision{}; // . + + Detail::PrintStyle PrintStyle = Detail::PrintStyle::Default; // U - L + + Detail::ShiftPrint ShiftPrint = Detail::ShiftPrint{}; // 0 - ' ' - * ..... + Detail::ShiftSize ShiftSize = Detail::ShiftSize{}; // ? - ^? + Detail::ShiftType ShiftType = Detail::ShiftType::Default; // < - > - ^ + + std::basic_string_view NextOverride = std::basic_string_view(nullptr, 0); + + std::uint8_t SpecifierCount = 0; + std::array, 10> Specifier {}; + + public: + static inline constexpr std::uint8_t NotFound() { return (std::numeric_limits::max)(); } + + FormatSpecifierType* GetSpecifier(const std::basic_string_view& name) { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + FormatSpecifierType* GetSpecifierOnlyText(const std::basic_string_view& name) { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].ValueHasText && Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + FormatSpecifierType* GetSpecifierOnlyNumber(const std::basic_string_view& name) { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].ValueHasNumber && Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + const FormatSpecifierType* GetSpecifier(const std::basic_string_view& name) const { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + bool HasSpecifier(const std::basic_string_view& name) const { + return GetSpecifier(name) != nullptr; + } + + const FormatSpecifierType* GetSpecifierOnlyText(const std::basic_string_view& name) const { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].ValueHasText && Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + const FormatSpecifierType* GetSpecifierOnlyNumber(const std::basic_string_view& name) const { + for (std::uint8_t i = 0; i < SpecifierCount; ++i) + if (Specifier[i].ValueHasNumber && Specifier[i].Name == name) + return &Specifier[i]; + return nullptr; + } + + std::basic_string_view GetSpecifierAsText(const std::basic_string_view& name, const std::basic_string_view& defaultValue = FormatSpecifierType::SpecifierAsTextNotSpecified) const { + const FormatSpecifierType* formatSpecifier = GetSpecifierOnlyText(name); + if (formatSpecifier == nullptr) + return defaultValue; + return formatSpecifier->ValueAsText; + } + + Detail::DataType GetSpecifierAsNumber(const std::basic_string_view& name, const Detail::DataType defaultValue = FormatSpecifierType::SpecifierAsNumberNotSpecified) const { + const FormatSpecifierType* formatSpecifier = GetSpecifierOnlyNumber(name); + if (formatSpecifier == nullptr) + return defaultValue; + return formatSpecifier->ValueAsNumber; + } + + void AddSpecifierForce(const FormatSpecifierType& specifier) + { + if (SpecifierCount < Specifier.size()) + Specifier[SpecifierCount++] = specifier; + } + + void AddSpecifier(const FormatSpecifierType& specifier, bool dontOverride = false) { + FormatSpecifierType* formatSpecifier = GetSpecifier(specifier.Name); + if (formatSpecifier == nullptr) + AddSpecifierForce(specifier); + else if (dontOverride == false) + { + if (specifier.ValueHasText) { + formatSpecifier->ValueHasText = true; + formatSpecifier->ValueAsText = specifier.ValueAsText; + } + if (specifier.ValueHasNumber) { + formatSpecifier->ValueHasNumber = true; + formatSpecifier->ValueAsNumber = specifier.ValueAsNumber; + } + } + } + + void AddSpecifier(const std::basic_string_view& name, const std::basic_string_view& value, bool dontOverride = false) { + FormatSpecifierType* formatSpecifier = GetSpecifier(name); + if (formatSpecifier == nullptr) + AddSpecifierForce(FormatSpecifierType(name, value)); + else if (dontOverride == false) + { + formatSpecifier->ValueHasText = true; + formatSpecifier->ValueAsText = value; + } + } + + void AddSpecifier(const std::basic_string_view& name, const Detail::DataType value, bool dontOverride = false) { + FormatSpecifierType* formatSpecifier = GetSpecifier(name); + if (formatSpecifier == nullptr) + AddSpecifierForce(FormatSpecifierType(name, value)); + else if (dontOverride == false) + { + formatSpecifier->ValueHasNumber = true; + formatSpecifier->ValueAsNumber = value; + } + } + + void AddSpecifier(const std::basic_string_view& name) { + FormatSpecifierType* formatSpecifier = GetSpecifier(name); + if (formatSpecifier == nullptr) + AddSpecifierForce(FormatSpecifierType(name)); + } + + public: + template void ModifyThrow(const T&) { throw Detail::FMTGivenTypeError{}; } + + void ModifyThrow(const FormatData& given) { *this = given; } + + void ModifyThrow(const Detail::ValueIntPrint& given) { IntPrint = given; } + void ModifyThrow(const Detail::PrintStyle& given) { PrintStyle = given; } + void ModifyThrow(const Detail::DigitSize& given) { DigitSize = given; } + void ModifyThrow(const Detail::ShiftSize& given) { ShiftSize = given; } + void ModifyThrow(const Detail::FloatPrecision& given) { FloatPrecision = given; } + void ModifyThrow(const Detail::ShiftPrint& given) { ShiftPrint = given; } + void ModifyThrow(const Detail::ShiftType& given) { ShiftType = given; } + void ModifyThrow(const FormatSpecifier& given) { AddSpecifier(given); } + + template bool ModifyTestThrow(const T* given) { + if (given == nullptr) + return false; + ModifyThrow(*given); + return true; + } + }; +} diff --git a/src/ProjectCore/FMT/Detail/TextProperties/BaseTextProperties.h b/src/ProjectCore/FMT/Detail/TextProperties/BaseTextProperties.h new file mode 100644 index 0000000..45cfc73 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/TextProperties/BaseTextProperties.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +// According to : https://en.wikipedia.org/wiki/ANSI_escape_code + +namespace ProjectCore::FMT::Detail +{ + struct TextProperties + { + struct ResetProperties {}; + + struct TextColor; + struct TextStyle; + struct TextFront; + + struct Properties; + }; +} diff --git a/src/ProjectCore/FMT/Detail/TextProperties/TextProperties.h b/src/ProjectCore/FMT/Detail/TextProperties/TextProperties.h new file mode 100644 index 0000000..a29833e --- /dev/null +++ b/src/ProjectCore/FMT/Detail/TextProperties/TextProperties.h @@ -0,0 +1,20 @@ +#pragma once + +#include "TextPropertiesColor.h" +#include "TextPropertiesStyle.h" +#include "TextPropertiesFront.h" + +namespace ProjectCore::FMT::Detail +{ + struct TextProperties::Properties + { + TextProperties::TextColor::Color Color; + TextProperties::TextStyle::Style Style; + TextProperties::TextFront::Front Front; + }; + + inline bool operator==(const TextProperties::Properties& lhs, const TextProperties::Properties& rhs) + { + return lhs.Color == rhs.Color && lhs.Style == rhs.Style && lhs.Front == rhs.Front; + } +} diff --git a/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesColor.h b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesColor.h new file mode 100644 index 0000000..e87195e --- /dev/null +++ b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesColor.h @@ -0,0 +1,485 @@ +#pragma once + +#include "BaseTextProperties.h" + +namespace ProjectCore::FMT::Detail +{ + struct TextProperties::TextColor + { + struct ResetColor {}; + + enum class BasicColorFG : std::uint8_t; + enum class BasicColorBG : std::uint8_t; + struct BasicColor; + + struct BaseColorCube; + struct ColorCubeFG; + struct ColorCubeBG; + struct ColorCube; + + struct BaseColor24b; + struct Color24bFG; + struct Color24bBG; + struct Color24b; + + enum class ColorType : std::uint8_t; + union ColorFGData; + union ColorBGData; + struct ColorData; + + struct ColorFG; + struct ColorBG; + struct Color; + }; + + enum class TextProperties::TextColor::BasicColorFG : std::uint8_t + { + Black = 30, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + White, + + BrightBlack = 90, + BrightRed, + BrightGreen, + BrightYellow, + BrightBlue, + BrightMagenta, + BrightCyan, + BrightWhite, + + Default = 39, + + BaseStep = Black, + BaseBStep = BrightBlack + }; + + enum class TextProperties::TextColor::BasicColorBG : std::uint8_t + { + Black = 40, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + White, + + BrightBlack = 100, + BrightRed, + BrightGreen, + BrightYellow, + BrightBlue, + BrightMagenta, + BrightCyan, + BrightWhite, + + Default = 49, + + BaseStep = Black, + BaseBStep = BrightBlack, + }; + + struct TextProperties::TextColor::BasicColor + { + constexpr BasicColor(TextProperties::TextColor::BasicColorFG fg = TextProperties::TextColor::BasicColorFG::Default, TextProperties::TextColor::BasicColorBG bg = TextProperties::TextColor::BasicColorBG::Default) + : Fg(fg), Bg(bg) { } + TextProperties::TextColor::BasicColorFG Fg; + TextProperties::TextColor::BasicColorBG Bg; + }; + + struct TextProperties::TextColor::BaseColorCube + { + public: + static inline constexpr std::uint8_t Black = 0; + static inline constexpr std::uint8_t Red = 1; + static inline constexpr std::uint8_t Green = 2; + static inline constexpr std::uint8_t Yellow = 3; + static inline constexpr std::uint8_t Blue = 4; + static inline constexpr std::uint8_t Magenta = 5; + static inline constexpr std::uint8_t Cyan = 6; + static inline constexpr std::uint8_t White = 7; + + static inline constexpr std::uint8_t BrightBlack = 8; + static inline constexpr std::uint8_t BrightRed = 9; + static inline constexpr std::uint8_t BrightGreen = 10; + static inline constexpr std::uint8_t BrightYellow = 11; + static inline constexpr std::uint8_t BrightBlue = 12; + static inline constexpr std::uint8_t BrightMagenta = 13; + static inline constexpr std::uint8_t BrightCyan = 14; + static inline constexpr std::uint8_t BrightWhite = 15; + + static inline constexpr std::uint8_t MinNormalColor = 0; + static inline constexpr std::uint8_t MaxNormalColor = 7; + static inline constexpr std::uint8_t MinBrightColor = 8; + static inline constexpr std::uint8_t MaxBrightColor = 15; + static inline constexpr std::uint8_t Min666CubeColor = 16; // 16 + 36 * r + 6 * g + b + static inline constexpr std::uint8_t Max666CubeColor = 231; + static inline constexpr std::uint8_t MinGrayscale = 232; // grayscale from black to white in 24 step + static inline constexpr std::uint8_t MaxGrayscale = 255; + + static inline constexpr std::uint8_t BaseStep = MinNormalColor; + static inline constexpr std::uint8_t BaseBStep = MinBrightColor; + static inline constexpr std::uint8_t Default = 0; + + public: + enum class Type : std::uint8_t + { + Normal, + Bright, + Cube666, + Grayscale + }; + + public: + std::uint8_t Color; + + public: + std::uint8_t GetColor() const { return Color; } + std::uint8_t GetColorRef() { return Color; } + std::uint8_t GetColorRef() const { return Color; } + + public: + constexpr BaseColorCube(const std::uint8_t color) + : Color(color) {} + + constexpr BaseColorCube() + : Color(0) {} + + Type GetType() + { + if (Color >= MinNormalColor && Color <= MaxNormalColor) + return Type::Normal; + else if (Color >= MinBrightColor && Color <= MaxBrightColor) + return Type::Bright; + else if (Color >= Min666CubeColor && Color <= Max666CubeColor) + return Type::Cube666; + else if (Color >= MinGrayscale && Color <= MaxGrayscale) + return Type::Grayscale; + return Type::Normal; + } + + static BaseColorCube MakeNormalColor(std::uint8_t value) { + if (value > MaxNormalColor) value -= MinBrightColor; + if (value > MaxNormalColor) value = MaxNormalColor; + return BaseColorCube(value); + } + + static BaseColorCube MakeBrightColor(std::uint8_t value) { + if (value < MinBrightColor) value += MinBrightColor; + if (value > MaxBrightColor) value = MaxBrightColor; + return BaseColorCube(value); + } + + static BaseColorCube Make666CubeColor255(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return Make666CubeColor5( static_cast((static_cast(r) / 255) * 5), + static_cast((static_cast(g) / 255) * 5), + static_cast((static_cast(b) / 255) * 5)); + } + + static BaseColorCube Make666CubeColor5(std::uint8_t r, std::uint8_t g, std::uint8_t b) { + if (r > 5) r = 5; + if (g > 5) g = 5; + if (b > 5) b = 5; + return BaseColorCube(Min666CubeColor + 36 * r + 6 * g + b); + } + + static BaseColorCube MakeGrayscaleColor255(const std::uint8_t value) { + return MakeGrayscaleColor24(static_cast(static_cast(value) / 255) * 24); + } + + static BaseColorCube MakeGrayscaleColor24(std::uint8_t value) { + if (value > 24) value = 24; + return BaseColorCube(MinGrayscale + value); + } + }; + + // No need of virtual destructor since ColorCubeFG is purely a renaming of BaseColorCube + struct TextProperties::TextColor::ColorCubeFG : public TextProperties::TextColor::BaseColorCube + { + public: + constexpr explicit ColorCubeFG() : TextProperties::TextColor::BaseColorCube() {} + constexpr explicit ColorCubeFG(const std::uint8_t color) : TextProperties::TextColor::BaseColorCube(color) {} + constexpr ColorCubeFG(const TextProperties::TextColor::BaseColorCube& color) : TextProperties::TextColor::BaseColorCube(color) {} + + public: + static ColorCubeFG MakeNormalColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeNormalColor(value)); + } + + static ColorCubeFG MakeBrightColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeBrightColor(value)); + } + + static ColorCubeFG Make666CubeColor255(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor255(r, g, b)); + } + + static ColorCubeFG Make666CubeColor5(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor5(r, g, b)); + } + + static ColorCubeFG MakeGrayscaleColor255(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor255(value)); + } + + static ColorCubeFG MakeGrayscaleColor24(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor24(value)); + } + }; + + // No need of virtual destructor since ColorCubeBG is purely a renaming of BaseColorCube + struct TextProperties::TextColor::ColorCubeBG : public TextProperties::TextColor::BaseColorCube + { + constexpr explicit ColorCubeBG() : TextProperties::TextColor::BaseColorCube() {} + constexpr explicit ColorCubeBG(const std::uint8_t color) : TextProperties::TextColor::BaseColorCube(color) {} + constexpr ColorCubeBG(const TextProperties::TextColor::BaseColorCube& color) : TextProperties::TextColor::BaseColorCube(color) {} + + public: + static TextProperties::TextColor::ColorCubeBG MakeNormalColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeNormalColor(value)); + } + + static TextProperties::TextColor::ColorCubeBG MakeBrightColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeBrightColor(value)); + } + + static TextProperties::TextColor::ColorCubeBG Make666CubeColor255(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor255(r, g, b)); + } + + static TextProperties::TextColor::ColorCubeBG Make666CubeColor5(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor5(r, g, b)); + } + + static TextProperties::TextColor::ColorCubeBG MakeGrayscaleColor255(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor255(value)); + } + + static TextProperties::TextColor::ColorCubeBG MakeGrayscaleColor24(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor24(value)); + } + }; + + inline bool operator==(const TextProperties::TextColor::BaseColorCube& lhs, const TextProperties::TextColor::BaseColorCube& rhs) + { + return lhs.Color == rhs.Color; + } + + struct TextProperties::TextColor::ColorCube + { + constexpr ColorCube() + : Fg() + , Bg() + {} + + constexpr ColorCube(const TextProperties::TextColor::ColorCubeFG& fg) + : Fg(fg) + , Bg() + {} + + constexpr ColorCube(const TextProperties::TextColor::ColorCubeFG& fg, const TextProperties::TextColor::ColorCubeBG& bg) + : Fg(fg) + , Bg(bg) + {} + + TextProperties::TextColor::ColorCubeFG Fg; + TextProperties::TextColor::ColorCubeBG Bg; + }; + + + struct TextProperties::TextColor::BaseColor24b + { + constexpr BaseColor24b(std::uint8_t r, std::uint8_t g, std::uint8_t b) + : R(r), G(g), B(b) { } + std::uint8_t R, G, B; + }; + + inline bool operator==(const TextProperties::TextColor::BaseColor24b& lhs, const TextProperties::TextColor::BaseColor24b& rhs) + { + return lhs.R == rhs.R && lhs.G == rhs.G && lhs.B == rhs.B; + } + + // No need of virtual destructor since Color24bFG is purely a renaming of BaseColor24b + struct TextProperties::TextColor::Color24bFG : public TextProperties::TextColor::BaseColor24b + { + constexpr Color24bFG(std::uint8_t r = 255, std::uint8_t g = 255, std::uint8_t b = 255) + : TextProperties::TextColor::BaseColor24b(r, g, b) {} + }; + + // No need of virtual destructor since Color24bBG is purely a renaming of BaseColor24b + struct TextProperties::TextColor::Color24bBG : public TextProperties::TextColor::BaseColor24b + { + constexpr Color24bBG(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0) + : TextProperties::TextColor::BaseColor24b(r, g, b) {} + }; + + + struct TextProperties::TextColor::Color24b + { + constexpr Color24b(const TextProperties::TextColor::Color24bFG&& fg = TextProperties::TextColor::Color24bFG(), const TextProperties::TextColor::Color24bBG&& bg = TextProperties::TextColor::Color24bBG()) + : Fg(fg), Bg(bg) { } + + TextProperties::TextColor::Color24bFG Fg; + TextProperties::TextColor::Color24bBG Bg; + }; + + inline bool operator==(const TextProperties::TextColor::Color24b& lhs, const TextProperties::TextColor::Color24b& rhs) + { + return lhs.Fg == rhs.Fg && lhs.Bg == rhs.Bg; + } + + enum class TextProperties::TextColor::ColorType : std::uint8_t + { + BasicColor, + ColorCube, + Color24b + }; + + union TextProperties::TextColor::ColorFGData + { + constexpr ColorFGData() + : BasicColor{ TextProperties::TextColor::BasicColorFG::Default } + {} + + TextProperties::TextColor::BasicColorFG BasicColor; + TextProperties::TextColor::ColorCubeFG ColorCube; + TextProperties::TextColor::Color24bFG Color24b; + }; + + union TextProperties::TextColor::ColorBGData + { + constexpr ColorBGData() + : BasicColor{ TextProperties::TextColor::BasicColorBG::Default } + {} + + TextProperties::TextColor::BasicColorBG BasicColor; + TextProperties::TextColor::ColorCubeBG ColorCube; + TextProperties::TextColor::Color24bBG Color24b; + }; + + struct TextProperties::TextColor::ColorFG + { + TextProperties::TextColor::ColorFGData Data; + TextProperties::TextColor::ColorType Type { TextProperties::TextColor::ColorType::BasicColor }; + }; + + struct TextProperties::TextColor::ColorBG + { + TextProperties::TextColor::ColorBGData Data; + TextProperties::TextColor::ColorType Type { TextProperties::TextColor::ColorType::BasicColor }; + }; + + inline bool operator==(const TextProperties::TextColor::ColorFG& lhs, const TextProperties::TextColor::ColorFG& rhs) + { + if (lhs.Type != rhs.Type) + return false; + switch(lhs.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: return lhs.Data.BasicColor == rhs.Data.BasicColor; + case TextProperties::TextColor::ColorType::ColorCube: return lhs.Data.ColorCube == rhs.Data.ColorCube; + case TextProperties::TextColor::ColorType::Color24b: return lhs.Data.Color24b == rhs.Data.Color24b; + } + return false; + } + + inline bool operator==(const TextProperties::TextColor::ColorBG& lhs, const TextProperties::TextColor::ColorBG& rhs) + { + if (lhs.Type != rhs.Type) + return false; + switch(lhs.Type) + { + case TextProperties::TextColor::ColorType::BasicColor: return lhs.Data.BasicColor == rhs.Data.BasicColor; + case TextProperties::TextColor::ColorType::ColorCube: return lhs.Data.ColorCube == rhs.Data.ColorCube; + case TextProperties::TextColor::ColorType::Color24b: return lhs.Data.Color24b == rhs.Data.Color24b; + } + return false; + } + + // Manage only the text color / the underline color will be manage by the TextProperties::TextStyle::UnderlineColor + struct TextProperties::TextColor::Color + { + public: + constexpr Color() + : Fg() + , Bg() + {} + + public: + TextProperties::TextColor::ColorFG Fg; + TextProperties::TextColor::ColorBG Bg; + + public: + void ModifyReset() + { + Fg = TextProperties::TextColor::ColorFG{}; + Bg = TextProperties::TextColor::ColorBG{}; + } + + template void ModifyThrow(const T&) { throw FMTGivenTypeError(); } + + void ModifyThrow(const Color& given) { *this = given; } + + void ModifyThrow(const TextProperties::TextColor::ResetColor&) { + ModifyReset(); + } + void ModifyThrow(const TextProperties::TextColor::BasicColorFG& given) { + Fg.Type = TextProperties::TextColor::ColorType::BasicColor; + Fg.Data.BasicColor = given; + } + void ModifyThrow(const TextProperties::TextColor::BasicColorBG& given) { + Bg.Type = TextProperties::TextColor::ColorType::BasicColor; + Bg.Data.BasicColor = given; + } + void ModifyThrow(const TextProperties::TextColor::ColorCubeFG& given) { + Fg.Type = TextProperties::TextColor::ColorType::ColorCube; + Fg.Data.ColorCube = given; + } + void ModifyThrow(const TextProperties::TextColor::ColorCubeBG& given) { + Bg.Type = TextProperties::TextColor::ColorType::ColorCube; + Bg.Data.ColorCube = given; + } + void ModifyThrow(const TextProperties::TextColor::Color24bFG& given) { + Fg.Type = TextProperties::TextColor::ColorType::Color24b; + Fg.Data.Color24b = given; + } + void ModifyThrow(const TextProperties::TextColor::Color24bBG& given) { + Bg.Type = TextProperties::TextColor::ColorType::Color24b; + Bg.Data.Color24b = given; + } + + public: + template bool NeedModif(const T&) { throw FMTGivenTypeError(); } + + bool NeedModif(const TextProperties::TextColor::ResetColor&) { + return true; + } + bool NeedModif(const TextProperties::TextColor::BasicColorFG& given) { + return Fg.Type != TextProperties::TextColor::ColorType::BasicColor || Fg.Data.BasicColor != given; + } + bool NeedModif(const TextProperties::TextColor::BasicColorBG& given) { + return Bg.Type != TextProperties::TextColor::ColorType::BasicColor || Bg.Data.BasicColor != given; + } + bool NeedModif(const TextProperties::TextColor::ColorCubeFG& given) { + return Fg.Type != TextProperties::TextColor::ColorType::ColorCube || Fg.Data.ColorCube != given; + } + bool NeedModif(const TextProperties::TextColor::ColorCubeBG& given) { + return Bg.Type != TextProperties::TextColor::ColorType::ColorCube || Bg.Data.ColorCube != given; + } + bool NeedModif(const TextProperties::TextColor::Color24bFG& given) { + return Fg.Type != TextProperties::TextColor::ColorType::Color24b || Fg.Data.Color24b != given; + } + bool NeedModif(const TextProperties::TextColor::Color24bBG& given) { + return Bg.Type != TextProperties::TextColor::ColorType::Color24b || Bg.Data.Color24b != given; + } + }; + + inline bool operator==(const TextProperties::TextColor::Color& lhs, const TextProperties::TextColor::Color& rhs) + { + return lhs.Fg == rhs.Fg && lhs.Bg == rhs.Bg; + } +} diff --git a/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesFront.h b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesFront.h new file mode 100644 index 0000000..ee46a9b --- /dev/null +++ b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesFront.h @@ -0,0 +1,60 @@ +#pragma once + +#include "BaseTextProperties.h" + +namespace ProjectCore::FMT::Detail +{ + struct TextProperties::TextFront + { + struct ResetFront {}; + + struct FrontID; + struct Front; + }; + + struct TextProperties::TextFront::FrontID + { + public: + static inline constexpr std::uint8_t DefaultFrontID = 10; + static inline constexpr std::uint8_t MinFrontID = 10; + static inline constexpr std::uint8_t MaxFrontID = 19; + + public: + std::uint8_t ID; + + constexpr FrontID() : ID(DefaultFrontID) {} + constexpr FrontID(std::uint8_t id) : ID(id) {} + + public: + constexpr bool operator==(const FrontID& other) const { return ID == other.ID; } + constexpr bool IsValid() const { return ID > MinFrontID && ID < MaxFrontID; } + }; + + struct TextProperties::TextFront::Front + { + public: + constexpr Front(const FrontID frontId = FrontID::DefaultFrontID) + : CurrentID(frontId.IsValid() ? frontId : FrontID::DefaultFrontID) + {} + + public: + FrontID CurrentID; + + public: + void ModifyReset() { *this = Front{}; } + + template void ModifyThrow(const T&) { throw Detail::FMTGivenTypeError{}; } + void ModifyThrow(const ResetFront&) { ModifyReset(); } + void ModifyThrow(const Front& given) { *this = given; } + void ModifyThrow(const FrontID& given) { CurrentID = given; } + + public: + template bool NeedModif(const T&) { throw Detail::FMTGivenTypeError{}; } + bool NeedModif(const ResetFront&) { return true; } + bool NeedModif(const Front& given) { return *this != given; } + bool NeedModif(const FrontID& given) { return CurrentID != given; } + + public: + bool operator==(const Front& other) const { return CurrentID == other.CurrentID; } + }; +} diff --git a/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesStyle.h b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesStyle.h new file mode 100644 index 0000000..616ee94 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/TextProperties/TextPropertiesStyle.h @@ -0,0 +1,257 @@ +#pragma once + +#include "BaseTextProperties.h" +#include "TextPropertiesColor.h" + +namespace ProjectCore::FMT::Detail +{ + struct TextProperties::TextStyle + { + struct ResetStyle {}; + + enum class Intensity : std::uint8_t; + enum class Italic : std::uint8_t; + enum class Blink : std::uint8_t; + enum class Inverted : std::uint8_t; + enum class Ideogram : std::uint8_t; + enum class Script : std::uint8_t; + enum class BasicStyle : std::uint8_t; + enum class Underline : std::uint8_t; + struct UnderlineColor; + + struct Style; + }; + + enum class TextProperties::TextStyle::Intensity : std::uint8_t + { + Bold = 1, + Dim = 2, + Normal = 22 + }; + + enum class TextProperties::TextStyle::Italic : std::uint8_t + { + Enable = 3, + Disable = 23 + }; + + enum class TextProperties::TextStyle::Underline : std::uint8_t + { + Underlined = 4, + DoubleUnerlined = 21, // may only disable bold + Disable = 24 + }; + + enum class TextProperties::TextStyle::Blink : std::uint8_t + { + SlowBlink = 5, + FastBlink = 6, + Disable = 25 + }; + + enum class TextProperties::TextStyle::Inverted : std::uint8_t + { + Enable = 7, + Disable = 27 + }; + + enum class TextProperties::TextStyle::Ideogram : std::uint8_t + { + Underlined = 60, + DoubleUnderlined = 61, + Overlined = 62, + DoubleOverlined = 63, + StressMarking = 64, + AllDisable = 65 + }; + + enum class TextProperties::TextStyle::Script : std::uint8_t + { + Superscript = 74, + Subscript = 75, + AllDisable = 76 + }; + + enum class TextProperties::TextStyle::BasicStyle : std::uint8_t + { + Intensity_Bold = static_cast(TextProperties::TextStyle::Intensity::Bold), + Intensity_Dim = static_cast(TextProperties::TextStyle::Intensity::Dim), + Intensity_Normal = static_cast(TextProperties::TextStyle::Intensity::Normal), + + Italic_Enable = static_cast(TextProperties::TextStyle::Italic::Enable), + Italic_Disable = static_cast(TextProperties::TextStyle::Italic::Disable), + + Underline_Underlined = static_cast(TextProperties::TextStyle::Underline::Underlined), + Underline_DoubleUnerlined = static_cast(TextProperties::TextStyle::Underline::DoubleUnerlined), // may only disable bold + Underline_Disable = static_cast(TextProperties::TextStyle::Underline::Disable), + Underline_SelectColor = 255, + + Blink_SlowBlink = static_cast(TextProperties::TextStyle::Blink::SlowBlink), + Blink_FastBlink = static_cast(TextProperties::TextStyle::Blink::FastBlink), + Blink_Disable = static_cast(TextProperties::TextStyle::Blink::Disable), + + Inverted_Enable = static_cast(TextProperties::TextStyle::Inverted::Enable), + Inverted_Disable = static_cast(TextProperties::TextStyle::Inverted::Disable), + + Ideogram_Underlined = static_cast(TextProperties::TextStyle::Ideogram::Underlined), + Ideogram_DoubleUnderlined = static_cast(TextProperties::TextStyle::Ideogram::DoubleUnderlined), + Ideogram_Overlined = static_cast(TextProperties::TextStyle::Ideogram::Overlined), + Ideogram_DoubleOverlined = static_cast(TextProperties::TextStyle::Ideogram::DoubleOverlined), + Ideogram_StressMarking = static_cast(TextProperties::TextStyle::Ideogram::StressMarking), + Ideogram_AllDisable = static_cast(TextProperties::TextStyle::Ideogram::AllDisable), + + Script_Superscript = static_cast(TextProperties::TextStyle::Script::Superscript), + Script_Subscript = static_cast(TextProperties::TextStyle::Script::Subscript), + Script_AllDisable = static_cast(TextProperties::TextStyle::Script::AllDisable) + }; + + struct TextProperties::TextStyle::UnderlineColor + { + struct ColorCube; + struct Color24b; + enum class ColorType : std::uint8_t; + union ColorData; + struct Color; + }; + + // No need of virtual destructor since Color24b is purely a renaming of BaseColor24b + struct TextProperties::TextStyle::UnderlineColor::Color24b : public TextProperties::TextColor::BaseColor24b + { + constexpr Color24b(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0) + : TextProperties::TextColor::BaseColor24b(r, g, b) {} + }; + + // No need of virtual destructor since ColorCube is purely a renaming of BaseColorCube + struct TextProperties::TextStyle::UnderlineColor::ColorCube : public TextProperties::TextColor::BaseColorCube + { + constexpr ColorCube() : TextProperties::TextColor::BaseColorCube() {} + constexpr ColorCube(const std::uint8_t color) : TextProperties::TextColor::BaseColorCube(color) {} + constexpr ColorCube(const TextProperties::TextColor::BaseColorCube& color) : TextProperties::TextColor::BaseColorCube(color) {} + + public: + static ColorCube MakeNormalColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeNormalColor(value)); + } + + static ColorCube MakeBrightColor(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeBrightColor(value)); + } + + static ColorCube Make666CubeColor255(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor255(r, g, b)); + } + + static ColorCube Make666CubeColor5(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b) { + return static_cast(TextProperties::TextColor::BaseColorCube::Make666CubeColor5(r, g, b)); + } + + static ColorCube MakeGrayscaleColor255(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor255(value)); + } + + static ColorCube MakeGrayscaleColor24(const std::uint8_t value) { + return static_cast(TextProperties::TextColor::BaseColorCube::MakeGrayscaleColor24(value)); + } + }; + + enum class TextProperties::TextStyle::UnderlineColor::ColorType : std::uint8_t + { + Default, + ColorCube, + Color24b + }; + + union TextProperties::TextStyle::UnderlineColor::ColorData + { + constexpr ColorData() + : ColorCube() + {} + + TextProperties::TextStyle::UnderlineColor::ColorCube ColorCube; + TextProperties::TextStyle::UnderlineColor::Color24b Color24b; + }; + + struct TextProperties::TextStyle::UnderlineColor::Color + { + TextProperties::TextStyle::UnderlineColor::ColorData Data; + TextProperties::TextStyle::UnderlineColor::ColorType Type = TextProperties::TextStyle::UnderlineColor::ColorType::Default; + }; + + inline bool operator==(const TextProperties::TextStyle::UnderlineColor::Color& lhs, const TextProperties::TextStyle::UnderlineColor::Color& rhs) + { + if (lhs.Type != rhs.Type) + return false; + switch(lhs.Type) + { + case TextProperties::TextStyle::UnderlineColor::ColorType::Default: return true; + case TextProperties::TextStyle::UnderlineColor::ColorType::ColorCube: return lhs.Data.ColorCube == rhs.Data.ColorCube; + case TextProperties::TextStyle::UnderlineColor::ColorType::Color24b: return lhs.Data.Color24b == rhs.Data.Color24b; + } + return false; + } + + bool operator==(const TextProperties::TextStyle::Style& lhs, const TextProperties::TextStyle::Style& rhs); + struct TextProperties::TextStyle::Style + { + public: + constexpr Style() {} + + TextProperties::TextStyle::Intensity Intensity = TextProperties::TextStyle::Intensity::Normal; + TextProperties::TextStyle::Italic Italic = TextProperties::TextStyle::Italic::Disable; + TextProperties::TextStyle::Blink Blink = TextProperties::TextStyle::Blink::Disable; + TextProperties::TextStyle::Inverted Inverted = TextProperties::TextStyle::Inverted::Disable; + TextProperties::TextStyle::Ideogram Ideogram = TextProperties::TextStyle::Ideogram::AllDisable; + TextProperties::TextStyle::Script Script = TextProperties::TextStyle::Script::AllDisable; + + TextProperties::TextStyle::Underline Underline = TextProperties::TextStyle::Underline::Disable; + TextProperties::TextStyle::UnderlineColor::Color UnderlineColor; + + public: + void ModifyReset() { *this = Style{}; } + + template void ModifyThrow(const T&) { throw Detail::FMTGivenTypeError{}; } + + void ModifyThrow(const TextProperties::TextStyle::ResetStyle&) { ModifyReset(); } + void ModifyThrow(const Style& given) { *this = given; } + void ModifyThrow(const TextProperties::TextStyle::Intensity& given) { Intensity = given; } + void ModifyThrow(const TextProperties::TextStyle::Italic& given) { Italic = given; } + void ModifyThrow(const TextProperties::TextStyle::Underline& given) { Underline = given; } + void ModifyThrow(const TextProperties::TextStyle::Blink& given) { Blink = given; } + void ModifyThrow(const TextProperties::TextStyle::Inverted& given) { Inverted = given; } + void ModifyThrow(const TextProperties::TextStyle::Ideogram& given) { Ideogram = given; } + void ModifyThrow(const TextProperties::TextStyle::Script& given) { Script = given; } + + void ModifyThrow(const TextProperties::TextStyle::UnderlineColor::Color& given) { UnderlineColor = given; } + void ModifyThrow(const TextProperties::TextStyle::UnderlineColor::ColorCube& given) { UnderlineColor.Type = TextProperties::TextStyle::UnderlineColor::ColorType::ColorCube; UnderlineColor.Data.ColorCube = given; } + void ModifyThrow(const TextProperties::TextStyle::UnderlineColor::Color24b& given) { UnderlineColor.Type = TextProperties::TextStyle::UnderlineColor::ColorType::Color24b; UnderlineColor.Data.Color24b = given; } + + public: + template bool NeedModif(const T&) { throw Detail::FMTGivenTypeError{}; } + + bool NeedModif(const TextProperties::TextStyle::ResetStyle&) { return true; } + bool NeedModif(const Style& given) { return *this != given; } + bool NeedModif(const TextProperties::TextStyle::Intensity& given) { return Intensity != given; } + bool NeedModif(const TextProperties::TextStyle::Italic& given) { return Italic != given; } + bool NeedModif(const TextProperties::TextStyle::Underline& given) { return Underline != given; } + bool NeedModif(const TextProperties::TextStyle::Blink& given) { return Blink != given; } + bool NeedModif(const TextProperties::TextStyle::Inverted& given) { return Inverted != given; } + bool NeedModif(const TextProperties::TextStyle::Ideogram& given) { return Ideogram != given; } + bool NeedModif(const TextProperties::TextStyle::Script& given) { return Script != given; } + + bool NeedModif(const TextProperties::TextStyle::UnderlineColor::Color& given) { return UnderlineColor != given; } + bool NeedModif(const TextProperties::TextStyle::UnderlineColor::ColorCube& given) { return UnderlineColor.Type != TextProperties::TextStyle::UnderlineColor::ColorType::ColorCube || UnderlineColor.Data.ColorCube != given; } + bool NeedModif(const TextProperties::TextStyle::UnderlineColor::Color24b& given) { return UnderlineColor.Type != TextProperties::TextStyle::UnderlineColor::ColorType::Color24b || UnderlineColor.Data.Color24b != given; } + }; + + inline bool operator==(const TextProperties::TextStyle::Style& lhs, const TextProperties::TextStyle::Style& rhs) + { + return lhs.Intensity == rhs.Intensity + && lhs.Italic == rhs.Italic + && lhs.Blink == rhs.Blink + && lhs.Inverted == rhs.Inverted + && lhs.Ideogram == rhs.Ideogram + && lhs.Script == rhs.Script + && lhs.Underline == rhs.Underline + && lhs.UnderlineColor == rhs.UnderlineColor; + } +} diff --git a/src/ProjectCore/FMT/Detail/Types/Types.h b/src/ProjectCore/FMT/Detail/Types/Types.h new file mode 100644 index 0000000..f020101 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Types/Types.h @@ -0,0 +1,214 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +#include +#include + +namespace ProjectCore::FMT::Detail +{ + using DataType = std::int32_t; + static inline constexpr DataType FORMAT_DATA_NOT_SPECIFIED = (std::numeric_limits::max)(); + + struct FormatIndex + { + public: + using BaseType = std::int32_t; + + public: + static inline constexpr DataType FORMAT_INDEX_NOT_SET = -1; + + public: + explicit constexpr FormatIndex(const BaseType index = FORMAT_INDEX_NOT_SET) + : Index(index) + , MaxValue((std::numeric_limits::max)()) + {} + + constexpr FormatIndex(const BaseType index, const BaseType maxValue) + : Index(index) + , MaxValue(maxValue) + {} + + public: + BaseType Index; + BaseType MaxValue; + + public: + constexpr bool IsValid() const { return Index >= 0 && Index < MaxValue; } + constexpr bool Is0() const { return Index == 0; } + + public: + constexpr FormatIndex& Next() { ++Index; return *this; } + constexpr FormatIndex& Prev() { --Index; return *this; } + + constexpr FormatIndex Get() const { return *this; } + constexpr FormatIndex GetAndNext() { FormatIndex old = *this; ++Index; return old; } + constexpr FormatIndex NextAndGet() { ++Index; return *this; } + constexpr FormatIndex GetNext() const { FormatIndex res = *this; ++res.Index; return res; } + + constexpr FormatIndex GetAndPrev() { FormatIndex old = *this; --Index; return old; } + constexpr FormatIndex PrevAndGet() { --Index; return *this; } + constexpr FormatIndex GetPrev() const { FormatIndex res = *this; --res.Index; return res; } + + constexpr void SetContext(FormatIndex sameContext) + { + MaxValue = sameContext.MaxValue; + } + }; + + + template + struct BasicCustomDataType; + + template concept EqualOperator = requires(const From& from, To& to) { to = from; }; + template concept AddEqualOperator = requires(const From& from, To& to) { to += from; }; + template concept MinusEqualOperator = requires(const From& from, To& to) { to -= from; }; + template concept MultEqualOperator = requires(const From& from, To& to) { to *= from; }; + template concept DivEqualOperator = requires(const From& from, To& to) { to /= from; }; + template concept IsEqualOperator = requires(const From& from, const To& to) { to == from; }; + template concept NotIsEqualOperator = requires(const From& from, const To& to) { to != from; }; + template concept LessThanOperator = requires(const From& from, const To& to) { to < from; }; + template concept LessEqualOperator = requires(const From& from, const To& to) { to <= from; }; + template concept GreaterThanOperator = requires(const From& from, const To& to) { to > from; }; + template concept GreaterEqualOperator = requires(const From& from, const To& to) { to >= from; }; + template concept AddOperator = requires(const From& from, const To& to) { to + from; }; + template concept MinusOperator = requires(const From& from, const To& to) { to - from; }; + template concept MultOperator = requires(const From& from, const To& to) { to * from; }; + template concept DivOperator = requires(const From& from, const To& to) { to / from; }; + + template concept DataTypeEqualOperator = requires(const From& from, To& to) { requires EqualOperator == false; to = from.Value; }; + template concept DataTypeAddEqualOperator = requires(const From& from, To& to) { requires AddEqualOperator == false; to += from.Value; }; + template concept DataTypeMinusEqualOperator = requires(const From& from, To& to) { requires MinusEqualOperator == false; to -= from.Value; }; + template concept DataTypeMultEqualOperator = requires(const From& from, To& to) { requires MultEqualOperator == false; to *= from.Value; }; + template concept DataTypeDivEqualOperator = requires(const From& from, To& to) { requires DivEqualOperator == false; to /= from.Value; }; + template concept DataTypeIsEqualOperator = requires(const From& from, const To& to) { requires IsEqualOperator == false; to == from.Value; }; + template concept DataTypeNotIsEqualOperator = requires(const From& from, const To& to) { requires NotIsEqualOperator == false; to != from.Value; }; + template concept DataTypeLessThanOperator = requires(const From& from, const To& to) { requires LessThanOperator == false; to < from.Value; }; + template concept DataTypeLessEqualOperator = requires(const From& from, const To& to) { requires LessEqualOperator == false; to <= from.Value; }; + template concept DataTypeGreaterThanOperator = requires(const From& from, const To& to) { requires GreaterThanOperator == false; to > from.Value; }; + template concept DataTypeGreaterEqualOperator = requires(const From& from, const To& to) { requires GreaterEqualOperator == false; to >= from.Value; }; + template concept DataTypeAddOperator = requires(const From& from, const To& to) { requires AddOperator == false; to + from.Value; }; + template concept DataTypeMinusOperator = requires(const From& from, const To& to) { requires MinusOperator == false; to - from.Value; }; + template concept DataTypeMultOperator = requires(const From& from, const To& to) { requires MultOperator == false; to * from.Value; }; + template concept DataTypeDivOperator = requires(const From& from, const To& to) { requires DivOperator == false; to / from.Value; }; + + template + struct BasicCustomDataType + { + public: + using ValueType = T; + + public: + static constexpr T DEFAULT = DEFAULT_VALUE; + static constexpr T INVALID = INVALID_VALUE; + + public: + T Value; + + public: + inline constexpr BasicCustomDataType(const T value = DEFAULT) + : Value(value) + {} + + public: + inline constexpr bool IsValid() { return Value != INVALID; } + inline constexpr bool IsDefault() { return Value == DEFAULT; } + + public: + inline constexpr operator T() const { return Value; } + + template + inline constexpr operator K() const requires std::is_convertible_v { return static_cast(Value); } + + public: + // operator +I + inline constexpr BasicCustomDataType operator+() const { return BasicCustomDataType(Value); } + // operator -I + inline constexpr BasicCustomDataType operator-() const { return BasicCustomDataType(-Value); } + + public: + // operator ++I + inline constexpr BasicCustomDataType& operator++() { ++Value; return *this; } + // operator --I + inline constexpr BasicCustomDataType& operator--() { --Value; return *this; } + // operator I++ + inline constexpr BasicCustomDataType operator++(int) { BasicCustomDataType res(Value); ++Value; return res; } + // operator I-- + inline constexpr BasicCustomDataType operator--(int) { BasicCustomDataType res(Value); --Value; return res; } + + public: + inline constexpr BasicCustomDataType& operator=(const EqualOperator auto i) { Value = i; return *this; } + inline constexpr BasicCustomDataType& operator+=(const AddEqualOperator auto i) { Value += i; return *this; } + inline constexpr BasicCustomDataType& operator-=(const MinusEqualOperator auto i) { Value -= i; return *this; } + inline constexpr BasicCustomDataType& operator*=(const MultEqualOperator auto i) { Value *= i; return *this; } + inline constexpr BasicCustomDataType& operator/=(const DivEqualOperator auto i) { Value /= i; return *this; } + + inline constexpr BasicCustomDataType& operator=(const DataTypeEqualOperator auto i) { Value = i.Value; return *this; } + inline constexpr BasicCustomDataType& operator+=(const DataTypeAddEqualOperator auto i) { Value += i.Value; return *this; } + inline constexpr BasicCustomDataType& operator-=(const DataTypeMinusEqualOperator auto i) { Value -= i.Value; return *this; } + inline constexpr BasicCustomDataType& operator*=(const DataTypeMultEqualOperator auto i) { Value *= i.Value; return *this; } + inline constexpr BasicCustomDataType& operator/=(const DataTypeDivEqualOperator auto i) { Value /= i.Value; return *this; } + }; + // operator + + template inline constexpr auto operator+(const AddOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs + rhs.Value; } + template inline constexpr auto operator+(const BasicCustomDataType& lhs, const AddOperator::ValueType> auto rhs) { return lhs.Value + rhs; } + // operator - + template inline constexpr auto operator-(const MinusOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs - rhs.Value; } + template inline constexpr auto operator-(const BasicCustomDataType& lhs, const MinusOperator::ValueType> auto rhs) { return lhs.Value - rhs; } + // operator * + template inline constexpr auto operator*(const MultOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs * rhs.Value; } + template inline constexpr auto operator*(const BasicCustomDataType& lhs, const MultOperator::ValueType> auto rhs) { return lhs.Value * rhs; } + // operator / + template inline constexpr auto operator/(const DivOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs / rhs.Value; } + template inline constexpr auto operator/(const BasicCustomDataType& lhs, const DivOperator::ValueType> auto rhs) { return lhs.Value / rhs; } + // operator + DataType + template inline constexpr auto operator+(const DataTypeAddOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value + rhs.Value; } + template inline constexpr auto operator+(const BasicCustomDataType& lhs, const DataTypeAddOperator::ValueType> auto rhs) { return lhs.Value + rhs.Value; } + // operator - DataType + template inline constexpr auto operator-(const DataTypeMinusOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value - rhs.Value; } + template inline constexpr auto operator-(const BasicCustomDataType& lhs, const DataTypeMinusOperator::ValueType> auto rhs) { return lhs.Value - rhs.Value; } + // operator * DataType + template inline constexpr auto operator*(const DataTypeMultOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Values * rhs.Value; } + template inline constexpr auto operator*(const BasicCustomDataType& lhs, const DataTypeMultOperator::ValueType> auto rhs) { return lhs.Value * rhs.Value; } + // operator / DataType + template inline constexpr auto operator/(const DataTypeDivOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value / rhs.Value; } + template inline constexpr auto operator/(const BasicCustomDataType& lhs, const DataTypeDivOperator::ValueType> auto rhs) { return lhs.Value / rhs.Value; } + + + // operator == + template inline constexpr bool operator==(const IsEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs == rhs.Value; } + template inline constexpr bool operator==(const BasicCustomDataType& lhs, const IsEqualOperator::ValueType> auto rhs) { return lhs.Value == rhs; } + // operator != + template inline constexpr bool operator!=(const NotIsEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs != rhs.Value; } + template inline constexpr bool operator!=(const BasicCustomDataType& lhs, const NotIsEqualOperator::ValueType> auto rhs) { return lhs.Value != rhs; } + // operator < + template inline constexpr bool operator<(const LessThanOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs < rhs.Value; } + template inline constexpr bool operator<(const BasicCustomDataType& lhs, const LessThanOperator::ValueType> auto rhs) { return lhs.Value < rhs; } + // operator > + template inline constexpr bool operator>(const GreaterThanOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs > rhs.Value; } + template inline constexpr bool operator>(const BasicCustomDataType& lhs, const GreaterThanOperator::ValueType> auto rhs) { return lhs.Value > rhs; } + // operator <= + template inline constexpr bool operator<=(const LessEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs <= rhs.Value; } + template inline constexpr bool operator<=(const BasicCustomDataType& lhs, const LessEqualOperator::ValueType> auto rhs) { return lhs.Value <= rhs; } + // operator >= + template inline constexpr bool operator>=(const GreaterEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs >= rhs.Value; } + template inline constexpr bool operator>=(const BasicCustomDataType& lhs, const GreaterEqualOperator::ValueType> auto rhs) { return lhs.Value >= rhs; } + // operator == DataType + template inline constexpr bool operator==(const DataTypeIsEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value == rhs.Value; } + template inline constexpr bool operator==(const BasicCustomDataType& lhs, const DataTypeIsEqualOperator::ValueType> auto rhs) { return lhs.Value == rhs.Value; } + // operator != DataType + template inline constexpr bool operator!=(const DataTypeNotIsEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value != rhs.Value; } + template inline constexpr bool operator!=(const BasicCustomDataType& lhs, const DataTypeNotIsEqualOperator::ValueType> auto rhs) { return lhs.Value != rhs.Value; } + // operator < DataType + template inline constexpr bool operator<(const DataTypeLessThanOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value < rhs.Value; } + template inline constexpr bool operator<(const BasicCustomDataType& lhs, const DataTypeLessThanOperator::ValueType> auto rhs) { return lhs.Value < rhs.Value; } + // operator > DataType + template inline constexpr bool operator>(const DataTypeGreaterThanOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value > rhs.Value; } + template inline constexpr bool operator>(const BasicCustomDataType& lhs, const DataTypeGreaterThanOperator::ValueType> auto rhs) { return lhs.Value > rhs.Value; } + // operator <= DataType + template inline constexpr bool operator<=(const DataTypeLessEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value <= rhs.Value; } + template inline constexpr bool operator<=(const BasicCustomDataType& lhs, const DataTypeLessEqualOperator::ValueType> auto rhs) { return lhs.Value <= rhs.Value; } + // operator >= DataType + template inline constexpr bool operator>=(const DataTypeGreaterEqualOperator::ValueType> auto lhs, const BasicCustomDataType& rhs) { return lhs.Value >= rhs.Value; } + template inline constexpr bool operator>=(const BasicCustomDataType& lhs, const DataTypeGreaterEqualOperator::ValueType> auto rhs) { return lhs.Value >= rhs.Value; } +} diff --git a/src/ProjectCore/FMT/Detail/Types/TypesInfo.h b/src/ProjectCore/FMT/Detail/Types/TypesInfo.h new file mode 100644 index 0000000..53451de --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Types/TypesInfo.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +namespace ProjectCore::FMT::Detail::TypesInfo +{ + template + struct NumberDetail { + bool IsFloatingNumber = std::is_floating_point_v; + bool IsSigned = std::is_signed_v; + }; +} diff --git a/src/ProjectCore/FMT/Detail/Types/TypesTraits.h b/src/ProjectCore/FMT/Detail/Types/TypesTraits.h new file mode 100644 index 0000000..d368ce2 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/Types/TypesTraits.h @@ -0,0 +1,76 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" + +#include + +namespace ProjectCore::FMT::Detail +{ + /////---------- Const PT ----------///// + + template + struct RemoveConstPt + { + using type = T; + }; + + template + struct RemoveConstPt + { + using type = T*; + }; + + template + struct RemoveConstPt + { + using type = T*; + }; + + template + using GetBaseType = typename RemoveConstPt>>::type; + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + template + struct IsCharType + { + using BaseType = GetBaseType; + static constexpr bool Value = std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + }; + + template + struct FMTCharTypeFromBuffer + { + using Type = void; + }; + + template + struct FMTCharTypeFromBuffer> { + using Type = GetBaseType; + }; + + template + struct FMTCharTypeFromBuffer> { + using Type = GetBaseType; + }; + + template + requires IsCharType::Value + struct FMTCharTypeFromBuffer + { + using Type = GetBaseType; + }; + + template + requires IsCharType::Value + struct FMTCharTypeFromBuffer + { + using Type = GetBaseType; + }; +} diff --git a/src/ProjectCore/FMT/Detail/UtilsContextsFunctions.h b/src/ProjectCore/FMT/Detail/UtilsContextsFunctions.h new file mode 100644 index 0000000..0a49e57 --- /dev/null +++ b/src/ProjectCore/FMT/Detail/UtilsContextsFunctions.h @@ -0,0 +1,22 @@ +#pragma once + +namespace ProjectCore::FMT::Detail +{ + template + struct ApplyNextOverrideForThisFunction { + inline explicit ApplyNextOverrideForThisFunction(FormatterContext& context) + : Context(context) + , FormatData(context.GetFormatData()) + { + Context.FormatDataApplyNextOverride(); + } + + inline ~ApplyNextOverrideForThisFunction() + { + Context.SetFormatData(FormatData); + } + + FormatterContext& Context; + typename FormatterContext::FormatDataType FormatData; + }; +} diff --git a/src/ProjectCore/FMT/FMT.h b/src/ProjectCore/FMT/FMT.h new file mode 100644 index 0000000..99ec1ce --- /dev/null +++ b/src/ProjectCore/FMT/FMT.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Context/FormatterContext/UtilityFunctions.h" +#include "Context/ParserContext/UtilityFunctions.h" + +#include "Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h" +#include "Detail/Buffer/BufferOutManager/GivenBufferOutManager.h" +#include "Detail/Buffer/BufferOutManager/StaticBufferOutManager.h" + +#include "Format/CompilationData.h" diff --git a/src/ProjectCore/FMT/Format/CompilationData.h b/src/ProjectCore/FMT/Format/CompilationData.h new file mode 100644 index 0000000..385935c --- /dev/null +++ b/src/ProjectCore/FMT/Format/CompilationData.h @@ -0,0 +1,78 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" +#include "ProjectCore/LoggerManager/LoggerManager.h" + +namespace ProjectCore::FMT::Detail +{ + struct FileLocation + { + FileLocation(std::string_view fileName, + int fileLine = 0) + : FileName(fileName) + , FileLine(fileLine) + {} + + std::string_view FileName; // __FILE__ + int FileLine; // __LINE__ + }; + + struct FunctionProperties + { + FunctionProperties(std::string_view fileName, + int fileLine = 0, + std::string_view functionName = "", + std::string_view functionSignature = "", + std::string_view functionAssemblyName = "") + : Location(fileName, fileLine) + , FunctionName(functionName) + , FunctionSignature(functionSignature) + , FunctionAssemblyName(functionAssemblyName) + {} + + FunctionProperties(FileLocation location, + std::string_view functionName = "", + std::string_view functionSignature = "", + std::string_view functionAssemblyName = "") + : Location(location) + , FunctionName(functionName) + , FunctionSignature(functionSignature) + , FunctionAssemblyName(functionAssemblyName) + {} + + FileLocation Location; + std::string_view FunctionName; // __FUNCTION__ + std::string_view FunctionSignature; // __FUNCSIG__ -- __PRETTY_FUNCTION__ + std::string_view FunctionAssemblyName; // __FUNCDNAME__ + }; +} + +#define PROJECTCORE_FMT_FILE_LOCATION() ProjectCore::FMT::Detail::FileLocation(__FILE__, __LINE__) +#define PROJECTCORE_FMT_FUNCTION_PROPERTIES() ProjectCore::FMT::Detail::FunctionProperties(PROJECTCORE_FMT_FILE_LOCATION(), __FUNCTION__, __FUNCSIG__, __FUNCDNAME__) + +namespace ProjectCore::FMT +{ + + template + struct FormatterType + { + static void Format(const Detail::FileLocation& t, FormatterContext& context) + { + context.RunType(t.FileName); + context.BufferOut().PushBack(':'); + context.RunType(t.FileLine); + } + }; + + template + struct FormatterType + { + static void Format(const Detail::FunctionProperties& t, FormatterContext& context) + { + context.RunType(t.Location); + context.BufferOut().WriteCharArray(" @ "); + context.RunType(t.FunctionName); + } + }; + +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_array.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_array.h new file mode 100644 index 0000000..0d7e209 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_array.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::array& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_deque.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_deque.h new file mode 100644 index 0000000..1e3f0ef --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_deque.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::deque& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_forward_list.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_forward_list.h new file mode 100644 index 0000000..53443dc --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_forward_list.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::forward_list& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_list.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_list.h new file mode 100644 index 0000000..8670a6a --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_list.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::list& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_map.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_map.h new file mode 100644 index 0000000..117ab2a --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_map.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +#include "FMT_tuple.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::map& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const std::multimap& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_queue.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_queue.h new file mode 100644 index 0000000..4b14e7b --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_queue.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::queue& t, FormatterContext& context) { + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_set.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_set.h new file mode 100644 index 0000000..9383b35 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_set.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::set& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const std::multiset& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_stack.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_stack.h new file mode 100644 index 0000000..e3d64a3 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_stack.h @@ -0,0 +1,16 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ +/* + template + struct FormatterType, FormatterContext> + { + static void Format(const std::stack& t, FormatterContext& context) { + } + }; +*/ +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_tuple.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_tuple.h new file mode 100644 index 0000000..e6033a1 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_tuple.h @@ -0,0 +1,57 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include +#include + +namespace ProjectCore::FMT::TupleDetail +{ + template using NthTypeOf = typename std::tuple_element>::type; + + template + constexpr NthTypeOf& Get(Args&& ...args) { + std::tuple tuple(args...); + return std::get(tuple); + } + + template + static void TupleFormatRec(FormatterContext& context) { } + + template + static void TupleFormatRec(FormatterContext& context, const T& t) { + context.WriteType(t); + } + + template + static void TupleFormatRec(FormatterContext& context, const T& t, Args&& ...args) { + context.WriteType(t); + context.BufferOut().PushBack(','); + context.BufferOut().PushBack(' '); + TupleFormatRec(context, args...); + } +} + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::tuple& t, FormatterContext& context) { + context.BufferOut().PushBack('<'); + std::apply([&context](auto&&... args) { TupleDetail::TupleFormatRec(context, args...); }, t); + context.BufferOut().PushBack('>'); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const std::pair& t, FormatterContext& context) { + context.BufferOut().PushBack('<'); + context.WriteType(t.first); + context.BufferOut().PushBack(':'); + context.WriteType(t.second); + context.BufferOut().PushBack('>'); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_map.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_map.h new file mode 100644 index 0000000..d69b813 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_map.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" + +#include +#include "FMT_tuple.h" + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::unordered_map& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const std::unordered_multimap& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_set.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_set.h new file mode 100644 index 0000000..639f439 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_unordered_set.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::unordered_set& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const std::unordered_multiset& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/FMT/Format/STDContainer/FMT_vector.h b/src/ProjectCore/FMT/Format/STDContainer/FMT_vector.h new file mode 100644 index 0000000..2277867 --- /dev/null +++ b/src/ProjectCore/FMT/Format/STDContainer/FMT_vector.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ProjectCore/FMT/Context/FormatterContext/FormatterType.h" +#include + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const std::vector& t, FormatterContext& context) { + FormatterType>, FormatterContext>::Format(t, context); + } + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/AllEvents.h b/src/ProjectCore/Instrumentation/ProfilerManger/AllEvents.h new file mode 100644 index 0000000..d0f39ee --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/AllEvents.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Event.h" + +namespace ProjectCore::Instrumentation +{ + class DurationEvent : public Event + { + public: + DurationEvent(const std::string& name, const std::string& category = "DurationEvent") + : Event(name, category, EventType::Complete) + {} + + DurationEvent(std::string&& name, std::string&& category = "DurationEvent") + : Event(std::move(name), std::move(category), EventType::Complete) + {} + + ~DurationEvent() override = default; + + public: + void Start() { Trigger(); } + void Stop() { Info.Duration = Instrumentation::GetMicroseconds() - Info.TimeOfEvent; } + }; + + class SampleEvent : public Event + { + public: + SampleEvent(const std::string& name, const std::string& category = "SampleEvent") + : Event(name, category, EventType::Sample) + {} + + SampleEvent(std::string&& name, std::string&& category) + : Event(std::move(name), std::move(category), EventType::Sample) + {} + + ~SampleEvent() override = default; + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/Detail.h b/src/ProjectCore/Instrumentation/ProfilerManger/Detail.h new file mode 100644 index 0000000..14fc416 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/Detail.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace ProjectCore::Instrumentation +{ + inline double GetMicroseconds() + { + return (double)std::chrono::time_point_cast(std::chrono::high_resolution_clock::now()).time_since_epoch().count() / 1000; + } +}; diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/Event.h b/src/ProjectCore/Instrumentation/ProfilerManger/Event.h new file mode 100644 index 0000000..d30f047 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/Event.h @@ -0,0 +1,136 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" +#include "ProjectCore/FMT/FMT.h" +#include "EventData.h" +#include "Detail.h" + +#include +#include + + +// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview + +namespace ProjectCore::Instrumentation +{ + int GetPid(); + + enum class EventType : char + { + Unknow = '.', + + DurationBegin = 'B', + DurationEnd = 'E', + + AsyncStart = 'b', + AsyncInstant = 'n', + AsyncEnd = 'e', + + FlowStart = 's', + FlowStep = 't', + FlowEnd = 'f', + + ObjectCreated = 'N', + ObjectSnapshot = 'O', + ObjectDestroyed = 'D', + + MemoryDumpGlobal = 'V', + MemoryDumpProcess = 'v', + + Complete = 'X', + Instant = 'i', + Counter = 'C', + Sample = 'P', + MetaData = 'M', + Mark = 'R', + ClockSyncEvents = 'c', + Context = ',' // '(' ')' + }; + + struct EventInfo + { + public: + EventInfo() + : Name("Unknow") + , Category("Unknow") + , Type(EventType::Unknow) + , Id(0) + , TimeOfEvent(Instrumentation::GetMicroseconds()) + , ThreadTimeOfEvent(0) + , Duration(0) + , PID(GetPid()) + , TID(std::hash{}(std::this_thread::get_id())) + , Data(nullptr) + {} + + EventInfo(const std::string& name, const std::string& category, EventType type, EventData* data = nullptr) + : Name(name) + , Category(category) + , Type(type) + , Id(0) + , TimeOfEvent(Instrumentation::GetMicroseconds()) + , ThreadTimeOfEvent(0) + , Duration(0) + , PID(GetPid()) + , TID(std::hash{}(std::this_thread::get_id())) + , Data(data) + {} + + EventInfo(std::string&& name, std::string&& category, EventType type, EventData* data = nullptr) + : Name(std::move(name)) + , Category(std::move(category)) + , Type(type) + , Id(0) + , TimeOfEvent(Instrumentation::GetMicroseconds()) + , ThreadTimeOfEvent(0) + , Duration(0) + , PID(GetPid()) + , TID(std::hash{}(std::this_thread::get_id())) + , Data(data) + {} + + public: + std::string Name; + std::string Category; + EventType Type; + std::size_t Id; + double TimeOfEvent, ThreadTimeOfEvent; + double Duration; + int PID; + std::size_t TID; + std::shared_ptr Data; + }; + + struct Event + { + public: + Event() = default; + + Event(const std::string& name, const std::string& category, EventType type, EventData* data = nullptr) + : Info(name, category, type, data) + {} + + Event(std::string&& name, std::string&& category, EventType type, EventData* data = nullptr) + : Info(std::move(name), std::move(category), type, data) + {} + + virtual ~Event() = default; + + public: + void Trigger() { Info.TimeOfEvent = Instrumentation::GetMicroseconds(); } + + public: + EventInfo Info; + }; +} + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const ProjectCore::Instrumentation::EventType& t, FormatterContext& context) { + context.BufferOut().PushBack(static_cast(t)); + } + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/EventData.h b/src/ProjectCore/Instrumentation/ProfilerManger/EventData.h new file mode 100644 index 0000000..5656704 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/EventData.h @@ -0,0 +1,33 @@ +#pragma once + +#include "ProjectCore/Json/Json.h" + +namespace ProjectCore::Instrumentation +{ + class EventData + { + public: + virtual ~EventData() = default; + + public: + virtual void ToJson(JSON::Detail::JsonFormatter& formatter) const = 0; + virtual void FromJson(JSON::Detail::JsonParser& parser) = 0; + }; + + class EventDataJsonObject final : public EventData + { + public: + ~EventDataJsonObject() override = default; + + public: + void ToJson(JSON::Detail::JsonFormatter& formatter) const override + { + JSON::JsonSerializer::Format(Data, formatter); + } + void FromJson(JSON::Detail::JsonParser& parser) override + { + JSON::JsonSerializer::Parse(Data, parser); + } + JSON::JsonStructObject Data; + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/GetPid.cpp b/src/ProjectCore/Instrumentation/ProfilerManger/GetPid.cpp new file mode 100644 index 0000000..deafdec --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/GetPid.cpp @@ -0,0 +1,25 @@ + +#ifdef PROJECTCORE_PLATFORM_LINUX + #include + #include +#endif + +#ifdef PROJECTCORE_PLATFORM_WINDOWS + #include + #include +#endif + +namespace ProjectCore::Instrumentation +{ + int GetPid() + { +#ifdef PROJECTCORE_PLATFORM_LINUX + return getpid(); +#endif + +#ifdef PROJECTCORE_PLATFORM_WINDOWS + return _getpid(); +#endif + return 0; + } +} \ No newline at end of file diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/Profiler.h b/src/ProjectCore/Instrumentation/ProfilerManger/Profiler.h new file mode 100644 index 0000000..7e3d9a2 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/Profiler.h @@ -0,0 +1,41 @@ +#pragma once + +#include "ProjectCore/Core/Core.h" +#include "ProjectCore/LoggerManager/LoggerManager.h" + +#include "Event.h" +#include "AllEvents.h" +#include "ProfilerEventCreator.h" + +namespace ProjectCore::Instrumentation +{ + class Profiler + { + public: + explicit Profiler(std::string&& name) + : Name(name) + , Logger(name) + , ProfilerDuration(name) + { + Events.clear(); + Events.push_back(EventInfo{}); + ProfilerDuration.Start(); + } + + ~Profiler() {} + + public: + void AddEvent(const Event& event) { AddEventInfo(event.Info); } + void AddEventInfo(const EventInfo& eventInfo) { Events.push_back(eventInfo); } + inline ProjectCore::LoggerManager::BasicLogger& GetLogger() { return Logger; } + + public: + static Profiler& GetInstance() { static Profiler profiler("Profiler"); return profiler; } + + public: + std::string Name; + LoggerManager::BasicLogger Logger; + DurationEvent ProfilerDuration; + std::vector Events; + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.cpp b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.cpp new file mode 100644 index 0000000..5fc0866 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.cpp @@ -0,0 +1,60 @@ +#include "ProfilerEventCreator.h" +#include "Profiler.h" + +namespace ProjectCore::Instrumentation +{ + ScopeProfile::~ScopeProfile() + { + Stop(); + + double millis = Info.Duration / 1000; + double sec = millis / 1000; + + if (sec > 1.5) m_Profiler.GetLogger().Trace("{} : {} seconds", Info.Name, sec); + else if (millis > 5.0) m_Profiler.GetLogger().Trace("{} : {} ms", Info.Name, millis); + else m_Profiler.GetLogger().Trace("{} : {} us", Info.Name, Info.Duration); + + m_Profiler.AddEvent(*this); + } + + + ObjectTracker::ObjectTracker(Profiler& profiler, const std::string& name, const std::string& category) + : m_Profiler(profiler) + , m_Name(name) + , m_Category(category) + { + Event created(m_Name, m_Category, EventType::ObjectCreated); + m_Profiler.AddEvent(created); + } + + ObjectTracker::ObjectTracker(Profiler& profiler, std::string&& name, std::string&& category) + : m_Profiler(profiler) + , m_Name(std::move(name)) + , m_Category(std::move(category)) + { + Event created(m_Name, m_Category, EventType::ObjectCreated); + created.Info.Id = 10; + m_Profiler.AddEvent(created); + } + + ObjectTracker::~ObjectTracker() + { + Event destroyed(m_Name, m_Category, EventType::ObjectDestroyed); + destroyed.Info.Id = 10; + m_Profiler.AddEvent(destroyed); + } + + void ObjectTracker::Snapshot() + { + Event snapshot(m_Name, m_Category, EventType::ObjectSnapshot); + snapshot.Info.Id = 10; + m_Profiler.AddEvent(snapshot); + } + + void EventCounter::Snapshot() + { + m_Idx++; + Event snapshot(m_Name, m_Category, EventType::Counter); + m_Profiler.AddEvent(snapshot); + } +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.h b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.h new file mode 100644 index 0000000..7f2e7b2 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerEventCreator.h @@ -0,0 +1,70 @@ +#pragma once + +#include "AllEvents.h" + +namespace ProjectCore::Instrumentation +{ + class Profiler; + + class ScopeProfile : public DurationEvent + { + public: + ScopeProfile(Profiler& profiler, const std::string& name, const std::string& category = "ScopeProfiler") + : DurationEvent(name, category) + , m_Profiler(profiler) + { Start(); } + + ScopeProfile(Profiler& profiler, std::string&& name, std::string&& category = "ScopeProfiler") + : DurationEvent(std::move(name), std::move(category)) + , m_Profiler(profiler) + { Start(); } + + ~ScopeProfile() override; + + private: + Profiler& m_Profiler; + }; + + class ObjectTracker + { + public: + ObjectTracker(Profiler& profiler, const std::string& name, const std::string& category = "Tracker"); + ObjectTracker(Profiler& profiler, std::string&& name, std::string&& category = "Tracker"); + virtual ~ObjectTracker(); + + public: + void Snapshot(); + + private: + Profiler& m_Profiler; + std::string m_Name; + std::string m_Category; + }; + + class EventCounter + { + public: + EventCounter(Profiler& profiler, const std::string& name, const std::string& category = "EventCounter") + : m_Profiler(profiler) + , m_Name(name) + , m_Category(category) + , m_Idx(0) + {} + + EventCounter(Profiler& profiler, std::string&& name, std::string&& category = "EventCounter") + : m_Profiler(profiler) + , m_Name(std::move(name)) + , m_Category(std::move(category)) + , m_Idx(0) + {} + + public: + void Snapshot(); + + private: + Profiler& m_Profiler; + std::string m_Name; + std::string m_Category; + std::uint64_t m_Idx; + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.cpp b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.cpp new file mode 100644 index 0000000..ba06d7f --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.cpp @@ -0,0 +1,21 @@ +#include "ProfilerFactory.h" +#include "ProfilerJsonSerializers.h" + +#include + +namespace ProjectCore::Instrumentation +{ + void ProfilerFactory::ToJson(Profiler& profiler, std::filesystem::path path) + { + profiler.ProfilerDuration.Stop(); + profiler.Events[0] = profiler.ProfilerDuration.Info; + + if (path == "") + path = std::string(profiler.Name) + ".json"; + + std::ofstream file(path.string(), std::ios::out); + JSON::FormatAsJson formatProfiler(profiler); + FMT::FilePrint(file, formatProfiler); + file.close(); + } +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.h b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.h new file mode 100644 index 0000000..a5e25fb --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerFactory.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Profiler.h" + +#include + +namespace ProjectCore::Instrumentation +{ + class ProfilerFactory + { + public: + static void ToJson(Profiler& profiler, std::filesystem::path path = ""); + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerJsonSerializers.h b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerJsonSerializers.h new file mode 100644 index 0000000..9b5d189 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerJsonSerializers.h @@ -0,0 +1,99 @@ +#pragma once + +#include "ProjectCore/Json/Json.h" +#include "ProfilerFactory.h" + +namespace ProjectCore::JSON +{ + template <> + struct JsonSerializer + { + static inline void Format(const Instrumentation::Profiler& t, Detail::JsonFormatter& formatter) + { + auto intermediate = formatter.GetStructIntermediate(); + intermediate.Format("displayTimeUnit", "us"); + intermediate.Format("traceEvents", t.Events); + } + + static inline void Parse(Instrumentation::Profiler& t, Detail::JsonParser& parser) + { + auto intermediate = parser.GetStructIntermediate(); + intermediate.Parse("traceEvents", t.Events); + } + }; + + template <> + struct JsonSerializer + { + static inline void Format(const Instrumentation::EventType& t, Detail::JsonFormatter& formatter) + { + formatter.Format(static_cast(t)); + } + + static inline void Parse(Instrumentation::EventType& t, Detail::JsonParser& parser) + { + parser.Parse(reinterpret_cast(t)); + } + }; + + template <> + struct JsonSerializer + { + static inline void Format(const Instrumentation::EventData& t, Detail::JsonFormatter& formatter) + { + t.ToJson(formatter); + } + + static inline void Parse(Instrumentation::EventData& t, Detail::JsonParser& parser) + { + t.FromJson(parser); + } + }; + + template <> + struct JsonSerializer + { + static inline void Format(const Instrumentation::EventInfo& t, Detail::JsonFormatter& formatter) + { + auto intermediate = formatter.GetStructIntermediate(); + intermediate.Format("name", t.Name); + intermediate.Format("cat", t.Category); + intermediate.Format("ph", t.Type); + intermediate.Format("pid", t.PID); + intermediate.Format("tid", t.TID); + intermediate.Format("ts", t.TimeOfEvent); + intermediate.Format("dur", t.Duration); + intermediate.Format("id", t.Id); + if (t.Data != nullptr) + intermediate.Format("args", *t.Data); + } + + static inline void Parse(Instrumentation::EventInfo& t, Detail::JsonParser& parser) + { + auto intermediate = parser.GetStructIntermediate(); + intermediate.Parse("name", t.Name); + intermediate.Parse("cat", t.Category); + intermediate.Parse("ph", t.Type); + intermediate.Parse("pid", t.PID); + intermediate.Parse("tid", t.TID); + intermediate.Parse("ts", t.TimeOfEvent); + intermediate.Parse("dur", t.Duration); + intermediate.Parse("id", t.Id); + intermediate.Parse("args", *t.Data); + } + }; + + template <> + struct JsonSerializer + { + static inline void Format(const Instrumentation::Event& t, Detail::JsonFormatter& formatter) + { + return JsonSerializer::Format(t.Info, formatter); + } + + static inline void Parse(Instrumentation::Event& t, Detail::JsonParser& parser) + { + return JsonSerializer::Parse(t.Info, parser); + } + }; +} diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerMacro.h b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerMacro.h new file mode 100644 index 0000000..a15c501 --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerMacro.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef PROJECTCORE_PROFILING_ENABLE + +#define PCP_PROFILE_FUNCTION() ProjectCore::Instrumentation::ScopeProfile profile##__LINE__(ProjectCore::Instrumentation::Profiler::GetInstance(), __FUNCSIG__, "Function") +#define PCP_PROFILE_FUNCTION_FMT(...) ProjectCore::Instrumentation::ScopeProfile profile##__LINE__(ProjectCore::Instrumentation::Profiler::GetInstance(), ProjectCore::Instrumentation::FMT::FormatString(__VA_ARGS__), "Function") +#define PCP_SAVE_DEFAULT_PROFILER() ProjectCore::Instrumentation::ProfilerFactory::ToJson(ProjectCore::Instrumentation::Profiler::GetInstance()) + +#else // PROJECTCORE_PROFILING_ENABLE + +#define PCP_PROFILE_FUNCTION() +#define PCP_PROFILE_FUNCTION_FMT(...) +#define PCP_SAVE_DEFAULT_PROFILER() + +#endif // PROJECTCORE_PROFILING_ENABLE diff --git a/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h new file mode 100644 index 0000000..a82318b --- /dev/null +++ b/src/ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h @@ -0,0 +1,4 @@ +#pragma once + +#include "Profiler.h" +#include "ProfilerFactory.h" diff --git a/src/ProjectCore/Json/Detail.h b/src/ProjectCore/Json/Detail.h new file mode 100644 index 0000000..accdad1 --- /dev/null +++ b/src/ProjectCore/Json/Detail.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +namespace ProjectCore::JSON::Detail +{ + class JsonError : public std::exception + { + public: + JsonError(std::string&& msg): m_What(std::move(msg)) {} + JsonError(const std::string_view msg): m_What(msg) {} + const char* what() const noexcept override { return m_What.c_str(); } + protected: + std::string m_What; + }; + + class JsonIndexingError : public JsonError + { + public: + JsonIndexingError(std::string&& msg = ""): JsonError(std::string("JsonIndexingError") + std::move(msg)) {} + JsonIndexingError(const std::string& msg): JsonError(std::string("JsonIndexingError") + msg) {} + }; + class JsonTypeSerializerNotImpl : public JsonError + { + public: + JsonTypeSerializerNotImpl(std::string&& msg = ""): JsonError(std::string("JsonTypeSerializerNotImpl") + std::move(msg)) {} + JsonTypeSerializerNotImpl(const std::string& msg): JsonError(std::string("JsonTypeSerializerNotImpl") + msg) {} + }; + class JsonGivenTypeError : public JsonError + { + public: + JsonGivenTypeError(std::string&& msg = ""): JsonError(std::string("JsonGivenTypeError") + std::move(msg)) {} + JsonGivenTypeError(const std::string& msg): JsonError(std::string("JsonGivenTypeError") + msg) {} + }; + class JsonCastError : public JsonError + { + public: + JsonCastError(std::string&& msg = ""): JsonError(std::string("JsonCastError") + std::move(msg)) {} + JsonCastError(const std::string& msg): JsonError(std::string("JsonCastError") + msg) {} + }; +} + +namespace ProjectCore::JSON +{ + template + struct JsonObjectSerializer; + template + struct JsonSerializer; +} + + + diff --git a/src/ProjectCore/Json/Json.h b/src/ProjectCore/Json/Json.h new file mode 100644 index 0000000..b642c02 --- /dev/null +++ b/src/ProjectCore/Json/Json.h @@ -0,0 +1,7 @@ +#pragma once + +#include "JsonObjects.h" +#include "JsonFactory.h" + +#include "JsonSerializer.h" +#include "Serializers/Serializers.h" diff --git a/src/ProjectCore/Json/JsonFactory.h b/src/ProjectCore/Json/JsonFactory.h new file mode 100644 index 0000000..77fba57 --- /dev/null +++ b/src/ProjectCore/Json/JsonFactory.h @@ -0,0 +1,84 @@ +#pragma once + +#include "JsonObjects.h" +#include "JsonFormatter.h" +#include "JsonFormatterImpl.h" +#include "JsonParser.h" +#include "JsonSerializer.h" +#include "Serializers/JsonObjectsSerializer.h" +#include "Serializers/Serializers.h" + +#include +#include + +namespace ProjectCore::JSON +{ + class JsonFactory + { + public: + template> + static T FromPath(const std::filesystem::path& path); + template + static void SaveToPath(T& json, const std::filesystem::path& path, Detail::JsonFormatter::FormatSettings settings); + }; +} + +#include "ProjectCore/FMT/FMT.h" +namespace ProjectCore::FMT +{ + template + struct FormatterType { + static void Format(const JSON::JsonObject& object, FormatterContext& context) + { + context.RunType(JSON::FormatAsJson(object)); + } + }; +} + +#include "ProjectCore//FMT/Detail/Buffer/BufferOutManager/DynamicBufferOutManager.h" +#include +#include +#include "Serializers/JsonObjectsSerializer.h" +namespace ProjectCore::JSON +{ + template + T JsonFactory::FromPath(const std::filesystem::path& path) + { + std::ifstream file(path.string(), std::ios::in); + + if (file.is_open() == false) + throw std::runtime_error("unable to open file"); + + std::string buffer; + + file.seekg(0, std::ios::end); + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + buffer.resize(static_cast(size)); + file.read(buffer.data(), size); + file.close(); + + FMT::Detail::BufferInProperties parserProperties(buffer.data(), buffer.size()); + Detail::JsonParser parser(parserProperties); + T res; + JsonSerializer::Parse(res, parser); + return res; + } + + template + void JsonFactory::SaveToPath(T& json, const std::filesystem::path& path, Detail::JsonFormatter::FormatSettings settings) + { + std::ofstream file(path.string(), std::ios::out); + + if (file.is_open() == false) + throw std::runtime_error("unable to open file"); + + FMT::Detail::DynamicBufferOutManager BufferOutManager(256); + Detail::JsonFormatter formatter(BufferOutManager, settings); + JsonSerializer::Format(json, formatter); + + file.write(BufferOutManager.GetBuffer(), static_cast(BufferOutManager.GetLastGeneratedDataSize())); + file.flush(); + file.close(); + } +} diff --git a/src/ProjectCore/Json/JsonFormatter.h b/src/ProjectCore/Json/JsonFormatter.h new file mode 100644 index 0000000..ee52abf --- /dev/null +++ b/src/ProjectCore/Json/JsonFormatter.h @@ -0,0 +1,113 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferOut/BasicBufferOut.h" +#include "JsonObjects.h" + +namespace ProjectCore::JSON::Detail +{ + class JsonFormatter + { + public: + using JsonBufferOut = ProjectCore::FMT::Detail::BasicBufferOut; + + struct FormatSettings + { + std::size_t IndentSize = 4; + bool IndentWithSpaces = true; + bool OneLine = false; + bool OrderedStruct = false; + ProjectCore::FMT::Detail::FloatPrecision FloatPrecision = 7; + }; + + public: + JsonFormatter(ProjectCore::FMT::Detail::BasicBufferOutManager& BufferOutManager) + : m_BufferOut(BufferOutManager) + , m_Indent(0) + , m_Settings() + {} + JsonFormatter(ProjectCore::FMT::Detail::BasicBufferOutManager& BufferOutManager, FormatSettings settings) + : m_BufferOut(BufferOutManager) + , m_Indent(0) + , m_Settings(settings) + {} + + public: + JsonBufferOut& BufferOut() { return m_BufferOut; } + const JsonBufferOut& BufferOut() const { return m_BufferOut; } + + FormatSettings& Settings() { return m_Settings; } + const FormatSettings& Settings() const { return m_Settings; } + + public: + template + void Format(const T& t); + + struct StructIntermediate; + struct ArrayIntermediate; + StructIntermediate GetStructIntermediate(); + ArrayIntermediate GetArrayIntermediate(); + + public: + void Indent() + { + if (m_Settings.OneLine) return; + + if (m_Settings.IndentWithSpaces) + m_BufferOut.PushBack(' ', m_Indent * m_Settings.IndentSize); + else + m_BufferOut.PushBack('\t', m_Indent * m_Settings.IndentSize); + } + + void NewLine() { if (m_Settings.OneLine) return; m_BufferOut.PushBack('\n'); Indent(); } + void BeginNewObject() { ++m_Indent; } + void EndNewObject() { --m_Indent; } + + protected: + JsonBufferOut m_BufferOut; + std::size_t m_Indent; + FormatSettings m_Settings; + }; +} + +namespace ProjectCore::JSON::Detail +{ + struct JsonFormatter::StructIntermediate + { + public: + StructIntermediate(JsonFormatter& formatter); + ~StructIntermediate(); + + public: + template + void Format(const std::string_view name, const T& t); + + public: + JsonFormatter& Formatter; + std::uint32_t Idx; + }; + + struct JsonFormatter::ArrayIntermediate + { + public: + ArrayIntermediate(JsonFormatter& formatter); + ~ArrayIntermediate(); + + public: + template + void Format(const T& t); + + public: + JsonFormatter& Formatter; + std::uint32_t Idx; + }; + + inline JsonFormatter::StructIntermediate JsonFormatter::GetStructIntermediate() + { + return JsonFormatter::StructIntermediate(*this); + } + + inline JsonFormatter::ArrayIntermediate JsonFormatter::GetArrayIntermediate() + { + return JsonFormatter::ArrayIntermediate(*this); + } +} diff --git a/src/ProjectCore/Json/JsonFormatterImpl.h b/src/ProjectCore/Json/JsonFormatterImpl.h new file mode 100644 index 0000000..ec65632 --- /dev/null +++ b/src/ProjectCore/Json/JsonFormatterImpl.h @@ -0,0 +1,39 @@ +#pragma once + +#include "JsonSerializer.h" + +namespace ProjectCore::JSON::Detail +{ + inline JsonFormatter::StructIntermediate::StructIntermediate(JsonFormatter& formatter) + : Formatter(formatter) + , Idx(0) + { + JsonStructSerializer::FormatBegin(Formatter); + } + inline JsonFormatter::StructIntermediate::~StructIntermediate() + { + JsonStructSerializer::FormatEnd(Formatter); + } + template + inline void JsonFormatter::StructIntermediate::Format(const std::string_view name, const T& t) + { + JsonStructSerializer::FormatObject(name, t, Idx++, Formatter); + } + + + inline JsonFormatter::ArrayIntermediate::ArrayIntermediate(JsonFormatter& formatter) + : Formatter(formatter) + , Idx(0) + { + JsonArraySerializer::FormatBegin(Formatter); + } + inline JsonFormatter::ArrayIntermediate::~ArrayIntermediate() + { + JsonArraySerializer::FormatEnd(Formatter); + } + template + inline void JsonFormatter::ArrayIntermediate::Format(const T& t) + { + JsonArraySerializer::FormatObject(t, Idx++, Formatter); + } +} diff --git a/src/ProjectCore/Json/JsonObjects.cpp b/src/ProjectCore/Json/JsonObjects.cpp new file mode 100644 index 0000000..8798956 --- /dev/null +++ b/src/ProjectCore/Json/JsonObjects.cpp @@ -0,0 +1,59 @@ +#include "JsonObjects.h" +#include "Serializers/JsonObjectsSerializer.h" + +namespace ProjectCore::JSON +{ + void JsonStringObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonStringObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } + + void JsonNumberObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonNumberObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } + + void JsonBooleanObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonBooleanObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } + + void JsonStructObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonStructObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } + + void JsonArrayObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonArrayObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } + + void JsonNullObject::ParserExecute(Detail::JsonParser& parser) + { + JsonSerializer::Parse(*this, parser); + } + void JsonNullObject::FormatterExecute(Detail::JsonFormatter& formatter) const + { + JsonSerializer::Format(*this, formatter); + } +} diff --git a/src/ProjectCore/Json/JsonObjects.h b/src/ProjectCore/Json/JsonObjects.h new file mode 100644 index 0000000..d90e2bb --- /dev/null +++ b/src/ProjectCore/Json/JsonObjects.h @@ -0,0 +1,212 @@ +#pragma once + +#include "Detail.h" +#include "ProjectCore/FMT/FMT.h" + +#include +#include +#include +#include +#include + +namespace ProjectCore::JSON::Detail +{ + class JsonParser; + class JsonFormatter; +} + +namespace ProjectCore::JSON +{ + struct JsonObject + { + public: + enum class ObjectType + { + String, + Number, + Boolean, + Struct, + Array, + Null, + Undefined + }; + + public: + JsonObject() {} + JsonObject(ObjectType type) : m_Type(type) {} + + virtual ~JsonObject() = default; + + private: + ObjectType m_Type = ObjectType::Undefined; + + public: + ObjectType GetType() { return m_Type; } + + JsonObject& operator[](const std::size_t index) { return Get(index); } + JsonObject& operator[](const std::string_view subObject) { return Get(subObject); } + + virtual JsonObject& Get(const std::size_t) { throw Detail::JsonIndexingError{}; } + virtual JsonObject& Get(const std::string_view) { throw Detail::JsonIndexingError{}; } + + public: + template + requires std::is_base_of_v + T& As() + { + T* t = dynamic_cast(this); + if (t == nullptr) + throw Detail::JsonCastError{}; + return *t; + } + + template + requires std::is_base_of_v + const T& As() const + { + const T* t = dynamic_cast(this); + if (t == nullptr) + throw Detail::JsonCastError{}; + return *t; + } + + template + T Read() + { + T value; + JsonObjectSerializer::ReadObject(value, *this); + return value; + } + + template + void Write(const T& t) + { + JsonObjectSerializer::WriteObject(t, *this); + } + + std::string ToString() { return FMT::FormatString(*this); } + + public: + virtual void ParserExecute(Detail::JsonParser& parser) = 0; + virtual void FormatterExecute(Detail::JsonFormatter& formatter) const = 0; + }; + + struct JsonStringObject final : public JsonObject + { + JsonStringObject() : JsonObject(ObjectType::String) {} + JsonStringObject(const std::string_view value) : JsonObject(ObjectType::String), String(value) {} + JsonStringObject(std::string&& value) : JsonObject(ObjectType::String), String(std::move(value)) {} + ~JsonStringObject() override = default; + + public: + std::string String; + + public: + static std::unique_ptr Create() { return std::make_unique(); } + static std::unique_ptr Create(const std::string_view value) { return std::make_unique(value); } + static std::unique_ptr Create(std::string&& value) { return std::make_unique(std::move(value)); } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; + + struct JsonNumberObject final : public JsonObject + { + JsonNumberObject(double value = 0.0) : JsonObject(ObjectType::Number), Number(value) {} + ~JsonNumberObject() override = default; + + public: + double Number; + + public: + static std::unique_ptr Create(double value = 0.0) { return std::make_unique(value); } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; + + struct JsonBooleanObject final : public JsonObject + { + JsonBooleanObject(bool value = false) : JsonObject(ObjectType::Boolean), Boolean(value) {} + ~JsonBooleanObject() override = default; + + public: + bool Boolean; + + public: + static std::unique_ptr Create(bool value = false) { return std::make_unique(value); } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; + + struct JsonStructObject final : public JsonObject + { + public: + JsonStructObject() : JsonObject(ObjectType::Struct) {} + ~JsonStructObject() override = default; + + public: + static std::unique_ptr Create() { return std::make_unique(); } + + public: + std::unordered_map> Objects; + + public: + void Add(const std::string& name, std::unique_ptr&& object) { Objects.insert({ name, std::move(object) }); } + void Add(std::string&& name, std::unique_ptr&& object) { Objects.insert({ std::move(name), std::move(object) }); } + JsonObject& Get(const std::string_view subObject) override + { + try + { + return *Objects.at(std::string(subObject)); + } + catch(...) + { + throw Detail::JsonIndexingError{}; + } + } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; + + struct JsonArrayObject final : public JsonObject + { + public: + JsonArrayObject() : JsonObject(ObjectType::Array) {} + ~JsonArrayObject() override = default; + + public: + static std::unique_ptr Create() { return std::make_unique(); } + + public: + std::vector> Objects; + + public: + void Add(std::unique_ptr&& object) { Objects.emplace_back(std::move(object)); } + JsonObject& Get(const std::size_t index) override { return *Objects[index]; } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; + + struct JsonNullObject final : public JsonObject + { + public: + JsonNullObject() : JsonObject(ObjectType::Null) {} + ~JsonNullObject() override = default; + + public: + static std::unique_ptr Create() { return std::make_unique(); } + + public: + void ParserExecute(Detail::JsonParser& parser) override; + void FormatterExecute(Detail::JsonFormatter& formatter) const override; + }; +} diff --git a/src/ProjectCore/Json/JsonParser.cpp b/src/ProjectCore/Json/JsonParser.cpp new file mode 100644 index 0000000..fff58dd --- /dev/null +++ b/src/ProjectCore/Json/JsonParser.cpp @@ -0,0 +1,76 @@ +#include "Detail.h" + +#include +#include +#include + +#include "JsonSerializer.h" + +namespace ProjectCore::JSON::Detail +{ + void JsonParser::Intermediate::Parse(Detail::JsonParser& parser) + { + parser.BufferIn().IgnoreAllBlanks(); + const char* begin = parser.BufferIn().GetBufferCurrentPos(); + + if (parser.IsJsonStringBegin()) + { + parser.BufferIn().Skip('"'); + while (true) + { + parser.BufferIn().GoTo('"'); + if (parser.BufferIn().PrevIsNotEqualTo('\\')) break; + } + parser.BufferIn().Skip('"'); + } + else if (parser.IsJsonNumberBegin()) + { + float k; + JsonNumberSerializer::ParseFloat(k, parser); + } + else if (parser.IsJsonBooleanBegin()) + { + bool k; + JsonBooleanSerializer::ParseBool(k, parser); + } + else if (parser.IsJsonStructBegin()) + { + JsonStructSerializer::LoadAllSubObjects(*this, parser, [](JsonParser::Intermediate&, std::size_t, std::string&&, JsonParser& jsonParser) { + JsonParser::Intermediate intermediate; + intermediate.Parse(jsonParser); + }); + } + else if (parser.IsJsonArrayBegin()) + { + JsonArraySerializer::LoadAllSubObjects(*this, parser, [](JsonParser::Intermediate&, std::size_t, JsonParser& jsonParser){ + JsonParser::Intermediate intermediate; + intermediate.Parse(jsonParser); + }); + } + else if (parser.IsJsonNullBegin()) + { + JsonNullSerializer::ParseNull(parser); + } + + const char* end = parser.BufferIn().GetBufferCurrentPos(); + Data = std::string_view(begin, end); + }; + + void JsonParser::StructIntermediate::Parse(Detail::JsonParser& parser) + { + JsonStructSerializer::LoadAllSubObjects(*this, parser, [](JsonParser::StructIntermediate& t, std::size_t, std::string&& name, JsonParser& jsonParser){ + JsonParser::Intermediate intermediate; + intermediate.Parse(jsonParser); + t.Objects.insert({std::move(name), std::move(intermediate)}); + }); + }; + + void JsonParser::ArrayIntermediate::Parse(Detail::JsonParser& parser) + { + JsonArraySerializer::LoadAllSubObjects(*this, parser, [](JsonParser::ArrayIntermediate& t, std::size_t, JsonParser& jsonParser){ + JsonParser::Intermediate intermediate; + intermediate.Parse(jsonParser); + t.Objects.emplace_back(std::move(intermediate)); + }); + }; +} diff --git a/src/ProjectCore/Json/JsonParser.h b/src/ProjectCore/Json/JsonParser.h new file mode 100644 index 0000000..97baa94 --- /dev/null +++ b/src/ProjectCore/Json/JsonParser.h @@ -0,0 +1,125 @@ +#pragma once + +#include "ProjectCore/FMT/Detail/Buffer/BasicBufferIn/BasicBufferIn.h" +#include "ProjectCore/FMT/Detail/Buffer/BufferInProperties/BufferInProperties.h" + +#include "JsonObjects.h" + +namespace ProjectCore::JSON::Detail +{ + class JsonParser + { + public: + using JsonBufferIn = FMT::Detail::BasicBufferIn; + + public: + JsonParser() + : m_BufferIn() + {} + + JsonParser(const FMT::Detail::BufferInProperties& bufferInProperties) + : m_BufferIn(bufferInProperties) + {} + + JsonParser(const char* const buffer, const std::size_t bufferSize) + : m_BufferIn(buffer, bufferSize) + {} + + public: + inline bool IsJsonStringBegin() const { return m_BufferIn.IsEqualTo('"'); } + inline bool IsJsonNumberBegin() const { return m_BufferIn.IsADigit() || m_BufferIn.IsEqualTo('+', '-', '.'); } + inline bool IsJsonBooleanBegin() const { return m_BufferIn.IsEqualTo('t', 'f'); } + inline bool IsJsonStructBegin() const { return m_BufferIn.IsEqualTo('{'); } + inline bool IsJsonArrayBegin() const { return m_BufferIn.IsEqualTo('['); } + inline bool IsJsonNullBegin() const { return m_BufferIn.IsEqualTo('n'); } + + public: + JsonBufferIn& BufferIn() { return m_BufferIn; } + const JsonBufferIn& BufferIn() const { return m_BufferIn; } + + protected: + JsonBufferIn m_BufferIn; + + public: + struct Intermediate; + + public: + template + void Parse(T& t); + + struct StructIntermediate; + struct ArrayIntermediate; + StructIntermediate GetStructIntermediate(); + ArrayIntermediate GetArrayIntermediate(); + }; +} + +namespace ProjectCore::JSON::Detail +{ + struct JsonParser::Intermediate + { + std::string_view Data; + + void Parse(Detail::JsonParser& parser); + + template + void Parse(T& t) + { + JsonParser parser; + parser.Parse(t); + } + }; + + struct JsonParser::StructIntermediate + { + public: + friend JsonParser; + + private: + std::unordered_map Objects; + + void Parse(Detail::JsonParser& parser); + + public: + template + void Parse(const std::string& name, T& t) + { + if (Objects.contains(name) == false) + throw Detail::JsonGivenTypeError{}; + Objects[name].Parse(t); + } + }; + + struct JsonParser::ArrayIntermediate + { + public: + friend JsonParser; + + private: + std::vector Objects; + + void Parse(Detail::JsonParser& parser); + + public: + template + void Parse(const std::size_t idx, T& t) + { + if (idx >= Objects.size()) + throw Detail::JsonGivenTypeError{}; + Objects[idx].Parse(t); + } + }; + + inline JsonParser::StructIntermediate JsonParser::GetStructIntermediate() + { + JsonParser::StructIntermediate res; + res.Parse(*this); + return res; + } + inline JsonParser::ArrayIntermediate JsonParser::GetArrayIntermediate() + { + JsonParser::ArrayIntermediate res; + res.Parse(*this); + return res; + } +} diff --git a/src/ProjectCore/Json/JsonSerializer.h b/src/ProjectCore/Json/JsonSerializer.h new file mode 100644 index 0000000..6539b99 --- /dev/null +++ b/src/ProjectCore/Json/JsonSerializer.h @@ -0,0 +1,383 @@ +#pragma once + +#include "JsonParser.h" +#include "JsonFormatter.h" + +#include "ProjectCore/FMT/Detail/Buffer/Utils/BufferUtils.h" +#include "ProjectCore/FMT/FMT.h" + +#include +#include + +namespace ProjectCore::JSON +{ + template + struct JsonSerializer + { + static inline void Parse(T&, Detail::JsonParser&) + { +#ifdef UNKOWN_TYPE_MESSAGE + FMT::FilePrint(std::cerr, "{C:red}JsonSerializer::Parse<{}> not impl", typeid(T).name()); +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + // FIXME + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + } + + static inline void Format(const T&, Detail::JsonFormatter& formatter) + { + formatter.BufferOut().FastWriteCharArray("Unkown JsonFormatter for type : "); + formatter.BufferOut().FastWriteCharPtrNSize(typeid(T).name()); + +#ifdef UNKOWN_TYPE_MESSAGE + FMT::FilePrint(std::cerr, "{C:red}JsonSerializer::Format<{}> not impl", typeid(T).name()); +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + // FIXME + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + } + }; + + template + struct JsonObjectSerializer + { + static inline void ReadObject(T&, const JsonObject&) + { +#ifdef UNKOWN_TYPE_MESSAGE + FMT::FilePrint(std::cerr, "{C:red}JsonObjectSerializer::ReadObject<{}> not impl", typeid(T).name()); +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + // FIXME + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + } + + static inline void WriteObject(const T&, JsonObject&) + { +#ifdef UNKOWN_TYPE_MESSAGE + FMT::FilePrint(std::cerr, "{C:red}JsonObjectSerializer::WriteObject<{}> not impl", typeid(T).name()); +#endif +#ifdef UNKOWN_TYPE_THROW + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_FAIL + // FIXME + throw Detail::JsonTypeSerializerNotImpl{}; +#endif +#ifdef UNKOWN_TYPE_DEBUG + PROJECTCORE_DEBUGBREAK(); +#endif + } + }; + + struct JsonStringSerializer + { + static inline void ParseSTDString(std::string& t, Detail::JsonParser& parser) + { + ProjectCore::FMT::Detail::DynamicBufferOutManager bufferData; + ProjectCore::FMT::Detail::BasicBufferOut buffer(bufferData); + ProjectCore::FMT::BufferUtils::ParseEscapedQuotedString(parser.BufferIn(), buffer); + buffer.EndContext(); + t = bufferData.GetLastGeneratedString(); + } + + static inline void FormatSTDString(const std::string_view t, Detail::JsonFormatter& formatter) + { + ProjectCore::FMT::Detail::BufferInProperties bufferInProperties(t); + ProjectCore::FMT::Detail::BasicBufferIn buffer(bufferInProperties); + ProjectCore::FMT::BufferUtils::FormatEscapedQuotedString(formatter.BufferOut(), buffer); + } + }; + + struct JsonNumberSerializer + { + template + static inline void ParseFloat(FloatType& t, Detail::JsonParser& parser) + { + parser.BufferIn().FastReadFloatThrow(t); + } + + template + static inline void ParseInt(IntType& t, Detail::JsonParser& parser) + { + const char* begin = parser.BufferIn().GetBufferCurrentPos(); + float tmp = 0; + parser.BufferIn().FastReadFloatThrow(tmp); + const char* end = parser.BufferIn().GetBufferCurrentPos(); + + parser.BufferIn().SetBufferCurrentPos(begin); + parser.BufferIn().FastReadIntThrow(t); + + parser.BufferIn().SetBufferCurrentPos(end); + } + + template + static inline void ParseUInt(UIntType& t, Detail::JsonParser& parser) + { + const char* begin = parser.BufferIn().GetBufferCurrentPos(); + float tmp = 0; + parser.BufferIn().FastReadFloatThrow(tmp); + const char* end = parser.BufferIn().GetBufferCurrentPos(); + + parser.BufferIn().SetBufferCurrentPos(begin); + parser.BufferIn().FastReadUIntThrow(t); + + parser.BufferIn().SetBufferCurrentPos(end); + } + + template + static inline void FormatFloat(const FloatType& t, Detail::JsonFormatter& formatter) + { + formatter.BufferOut().FastWriteFloat(t, formatter.Settings().FloatPrecision); + } + + template + static inline void FormatInt(const IntType& t, Detail::JsonFormatter& formatter) + { + formatter.BufferOut().FastWriteInt(t); + } + + template + static inline void FormatUInt(const UIntType& t, Detail::JsonFormatter& formatter) + { + formatter.BufferOut().FastWriteUInt(t); + } + }; + + struct JsonBooleanSerializer + { + static inline void ParseBool(bool& t, Detail::JsonParser& parser) + { + if (parser.BufferIn().IsSameSeqForward('t', 'r', 'u', 'e')) + t = true; + else if (parser.BufferIn().IsSameSeqForward('f', 'a', 'l', 's', 'e')) + t = false; + } + + static inline void FormatBool(const bool& t, Detail::JsonFormatter& formatter) + { + if (t) + formatter.BufferOut().PushBackSeq('t', 'r', 'u', 'e'); + else + formatter.BufferOut().PushBackSeq('f', 'a', 'l', 's', 'e'); + } + }; + + struct JsonStructSerializer + { + template + static inline void LoadAllSubObjects(T& t, Detail::JsonParser& parser, std::function subObjectParsingFunction) + { + parser.BufferIn().Skip('{'); + std::size_t idx = 0; + + while (parser.BufferIn().IsEnd() == false) + { + parser.BufferIn().GoTo('"', '}'); + if (parser.BufferIn().IsEqualTo('}')) break; + + std::string name; + JsonStringSerializer::ParseSTDString(name, parser); + + parser.BufferIn().IgnoreAllBlanks(); + parser.BufferIn().Skip(':'); + parser.BufferIn().IgnoreAllBlanks(); + + subObjectParsingFunction(t, idx++, std::move(name), parser); + + parser.BufferIn().GoTo(',', '}'); + parser.BufferIn().Ignore(','); + } + + parser.BufferIn().Skip('}'); + } + + template + static inline void LoadAllSubObjects(T& t, Detail::JsonParser& parserObject) + { + LoadAllSubObjects(t, parserObject, [](T& mainObject, std::size_t idx, std::string&& name, Detail::JsonParser& parser){ + typename JsonSerializer::StructSubObjectType subObject; + parser.Parse(subObject); + JsonSerializer::AddStructSubObject(mainObject, idx, std::move(name), std::move(subObject)); + }); + } + + static inline void FormatBegin(Detail::JsonFormatter& formatter) + { + formatter.BufferOut().PushBack('{'); + } + + static inline void FormatEnd(Detail::JsonFormatter& formatter) + { + formatter.NewLine(); + formatter.BufferOut().PushBack('}'); + } + + template + static inline void FormatObject(const std::string_view name, const SubObject& subObject, const std::size_t idx, Detail::JsonFormatter& formatter) + { + if (idx != 0) formatter.BufferOut().PushBack(','); + + formatter.BeginNewObject(); + formatter.NewLine(); + JsonStringSerializer::FormatSTDString(name, formatter); + formatter.BufferOut().PushBack(':'); + formatter.BufferOut().PushBack(' '); + formatter.Format(subObject); + formatter.EndNewObject(); + } + }; + + struct JsonArraySerializer + { + template + static inline void LoadAllSubObjects(T& t, Detail::JsonParser& parser, std::function subObjectParsingFunction) + { + parser.BufferIn().Skip('['); + std::size_t idx = 0; + + while (parser.BufferIn().IsEnd() == false) + { + parser.BufferIn().IgnoreAllBlanks(); + + if (parser.BufferIn().IsEqualTo(']')) break; + + subObjectParsingFunction(t, idx++, parser); + + parser.BufferIn().GoTo(',', ']'); + parser.BufferIn().Ignore(','); + } + + parser.BufferIn().Skip(']'); + } + + template + static inline void LoadAllSubObjects(T& t, Detail::JsonParser& parser) + { + LoadAllSubObjects(t, parser, [](T& mainObject, std::size_t idx, Detail::JsonParser& jsonParser){ + typename JsonSerializer::ArraySubObjectType subObject; + jsonParser.Parse(subObject); + JsonSerializer::AddArraySubObject(mainObject, idx, std::move(subObject)); + }); + } + + static inline void FormatBegin(Detail::JsonFormatter& formatter) + { + formatter.BufferOut().PushBack('['); + } + + static inline void FormatEnd(Detail::JsonFormatter& formatter) + { + formatter.NewLine(); + formatter.BufferOut().PushBack(']'); + } + + template + static inline void FormatObject(const SubObject& subObject, const std::size_t idx, Detail::JsonFormatter& formatter) + { + if (idx != 0) formatter.BufferOut().PushBack(','); + + formatter.BeginNewObject(); + formatter.NewLine(); + formatter.Format(subObject); + formatter.EndNewObject(); + } + }; + + struct JsonNullSerializer + { + static inline void ParseNull(Detail::JsonParser& parser) + { + parser.BufferIn().IsSameSeqForwardThrow('n', 'u', 'l', 'l'); + } + + static inline void FormatNull(Detail::JsonFormatter& formatter) + { + formatter.BufferOut().PushBackSeq('n', 'u', 'l', 'l'); + } + }; +} + +namespace ProjectCore::JSON::Detail +{ + template + void JsonFormatter::Format(const T& t) + { + JsonSerializer::Format(t, *this); + } + + template + void JsonParser::Parse(T& t) + { + JsonSerializer::Parse(t, *this); + } +} + +namespace ProjectCore::JSON +{ + template + struct FormatAsJson + { + public: + FormatAsJson(const T& value) + : Value(value) + {} + + public: + const T& Value; + }; +} + +#include "ProjectCore/FMT/FMT.h" +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const JSON::FormatAsJson& json, FormatterContext& context) + { + bool ordered_struct = context.GetFormatData().HasSpecifier("ordered_struct"); + JSON::Detail::JsonFormatter::FormatSettings settings{ + .OrderedStruct = ordered_struct, + .FloatPrecision = context.GetFormatData().FloatPrecision + }; + JSON::Detail::JsonFormatter jsonFormatter(context.BufferOut().GetBufferOutManager(), settings); + jsonFormatter.BufferOut().ReloadBuffer(context.BufferOut()); + JSON::JsonSerializer::Format(json.Value, jsonFormatter); + context.BufferOut().ReloadBuffer(jsonFormatter.BufferOut()); + } + }; + + template + struct ParserType, ParserContext> + { + static inline void Parse(T& json, ParserContext& context) + { + JSON::Detail::JsonParser jsonParser(context.BufferIn().GetBufferOutManager()); + jsonParser.BufferIn().ReloadBuffer(context.BufferIn()); + // TODO: + // JSON::JsonSerializer::Parse(json.Value, jsonParser); + context.BufferIn().ReloadBuffer(jsonParser.BufferIn()); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/BaseSerializers.h b/src/ProjectCore/Json/Serializers/BaseSerializers.h new file mode 100644 index 0000000..7817074 --- /dev/null +++ b/src/ProjectCore/Json/Serializers/BaseSerializers.h @@ -0,0 +1,464 @@ +#pragma once + +#include "../JsonObjects.h" +#include "../JsonSerializer.h" + +#include "ProjectCore/FMT/Detail/Forwarders.h" + +#include + +namespace ProjectCore::JSON +{ + // Int Types + template <> + struct JsonSerializer + { + static inline void Parse(std::int8_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseInt(t, parser); + } + static inline void Format(const std::int8_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::int16_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseInt(t, parser); + } + static inline void Format(const std::int16_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::int32_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseInt(t, parser); + } + static inline void Format(const std::int32_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::int64_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseInt(t, parser); + } + static inline void Format(const std::int64_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatInt(t, formatter); + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::int8_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::int8_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::int16_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::int16_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::int32_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::int32_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::int64_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::int64_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + + + // UInt Types + template <> + struct JsonSerializer + { + static inline void Parse(std::uint8_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseUInt(t, parser); + } + static inline void Format(const std::uint8_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatUInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::uint16_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseUInt(t, parser); + } + static inline void Format(const std::uint16_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatUInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::uint32_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseUInt(t, parser); + } + static inline void Format(const std::uint32_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatUInt(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(std::uint64_t& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseUInt(t, parser); + } + static inline void Format(const std::uint64_t& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatUInt(t, formatter); + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::uint8_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::uint8_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::uint16_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::uint16_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::uint32_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::uint32_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(std::uint64_t& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const std::uint64_t& t, JsonObject& object) { + object.As().Number = t; + } + }; + + // Float Types + template <> + struct JsonSerializer + { + static inline void Parse(float& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseFloat(t, parser); + } + static inline void Format(const float& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatFloat(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(double& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseFloat(t, parser); + } + static inline void Format(const double& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatFloat(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(long double& t, Detail::JsonParser& parser) { + JsonNumberSerializer::ParseFloat(t, parser); + } + static inline void Format(const long double& t, Detail::JsonFormatter& formatter) { + JsonNumberSerializer::FormatFloat(t, formatter); + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(float& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const float& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(double& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const double& t, JsonObject& object) { + object.As().Number = t; + } + }; + template <> + struct JsonObjectSerializer + { + static inline void ReadObject(long double& t, const JsonObject& object) { + t = object.As().Number; + } + static inline void WriteObject(const long double& t, JsonObject& object) { + object.As().Number = t; + } + }; + + + template + struct JsonSerializer> + { + static inline void Parse(Char& t, Detail::JsonParser& parser) { + parser.BufferIn().Skip('"'); + t = static_cast(parser.BufferIn().GetAndForward()); + parser.BufferIn().Skip('"'); + } + static inline void Format(const Char& t, Detail::JsonFormatter& formatter) { + formatter.BufferOut().PushBack('"'); + formatter.BufferOut().PushBack(static_cast(t)); + formatter.BufferOut().PushBack('"'); + } + }; + template + struct JsonSerializer> + { + static inline void Parse([[maybe_unused]] Char(&t)[SIZE], Detail::JsonParser& parser) { + parser.BufferIn().Skip('"'); + parser.BufferIn().Skip('"'); + } + static inline void Format([[maybe_unused]] const Char(&t)[SIZE], Detail::JsonFormatter& formatter) { + formatter.BufferOut().PushBack('"'); + formatter.BufferOut().PushBack('"'); + } + }; + template + struct JsonSerializer> + { + static inline void Parse([[maybe_unused]] Char* t, Detail::JsonParser& parser) { + parser.BufferIn().Skip('"'); + parser.BufferIn().Skip('"'); + } + static inline void Format([[maybe_unused]] const Char* t, Detail::JsonFormatter& formatter) { + formatter.BufferOut().PushBack('"'); + formatter.BufferOut().PushBack('"'); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(char& t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char& t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(wchar_t& t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const wchar_t& t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char8_t& t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char8_t& t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char16_t& t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char16_t& t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char32_t& t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char32_t& t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + + template + struct JsonSerializer + { + static inline void Parse(char(&t)[SIZE], Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template + struct JsonSerializer + { + static inline void Parse(wchar_t(&t)[SIZE], Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const wchar_t(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template + struct JsonSerializer + { + static inline void Parse(char8_t(&t)[SIZE], Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char8_t(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template + struct JsonSerializer + { + static inline void Parse(char16_t(&t)[SIZE], Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char16_t(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template + struct JsonSerializer + { + static inline void Parse(char32_t(&t)[SIZE], Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char32_t(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(char* t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char* t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(wchar_t* t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const wchar_t* t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char8_t* t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char8_t* t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char16_t* t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char16_t* t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + template <> + struct JsonSerializer + { + static inline void Parse(char32_t* t, Detail::JsonParser& parser) { + JsonSerializer>::Parse(t, parser); + } + static inline void Format(const char32_t* t, Detail::JsonFormatter& formatter) { + JsonSerializer>::Format(t, formatter); + } + }; + + template + struct JsonSerializer + { + static inline void Parse(T* t, Detail::JsonParser& parser) { + if (t == nullptr) throw Detail::JsonGivenTypeError{}; + JsonSerializer::Parse(*t, parser); + } + static inline void Format(const T* t, Detail::JsonFormatter& formatter) { + if (t == nullptr) throw Detail::JsonGivenTypeError{}; + JsonSerializer::Format(*t, formatter); + } + }; + + template + struct JsonSerializer + { + using ArraySubObjectType = T; + + static inline void Parse(T(&t)[SIZE], Detail::JsonParser& parser) { + JsonArraySerializer::LoadAllSubObjects(t, parser); + } + static inline void AddArraySubObject(T(&t)[SIZE], std::size_t idx, ArraySubObjectType&& subObject) { + t[idx] = std::move(subObject); + } + + static inline void Format(const T(&t)[SIZE], Detail::JsonFormatter& formatter) { + JsonArraySerializer::FormatBegin(formatter); + for (std::size_t idx = 0; idx < SIZE; ++idx) + JsonArraySerializer::FormatObject(t[idx], idx, formatter); + JsonArraySerializer::FormatEnd(formatter); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/JsonObjectsSerializer.h b/src/ProjectCore/Json/Serializers/JsonObjectsSerializer.h new file mode 100644 index 0000000..0e34473 --- /dev/null +++ b/src/ProjectCore/Json/Serializers/JsonObjectsSerializer.h @@ -0,0 +1,137 @@ +#pragma once + +#include "../JsonObjects.h" +#include "../JsonSerializer.h" + +#include "STDSerializers/JSON_vector.h" +#include "STDSerializers/JSON_unordered_map.h" + +#include + +namespace ProjectCore::JSON +{ + template <> + struct JsonSerializer> + { + static inline void Parse(std::unique_ptr& t, Detail::JsonParser& parser) + { + parser.BufferIn().IgnoreAllBlanks(); + if (parser.IsJsonStringBegin()) + t = std::make_unique(); + else if (parser.IsJsonNumberBegin()) + t = std::make_unique(); + else if (parser.IsJsonBooleanBegin()) + t = std::make_unique(); + else if (parser.IsJsonStructBegin()) + t = std::make_unique(); + else if (parser.IsJsonArrayBegin()) + t = std::make_unique(); + else if (parser.IsJsonNullBegin()) + t = std::make_unique(); + + t->ParserExecute(parser); + } + + static inline void Format(const std::unique_ptr& t, Detail::JsonFormatter& formatter) + { + t->FormatterExecute(formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Format(const JsonObject& t, Detail::JsonFormatter& formatter) + { + t.FormatterExecute(formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonStringObject& t, Detail::JsonParser& parser) + { + t.String.clear(); + JsonStringSerializer::ParseSTDString(t.String, parser); + } + + static inline void Format(const JsonStringObject& t, Detail::JsonFormatter& formatter) + { + JsonStringSerializer::FormatSTDString(t.String, formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonNumberObject& t, Detail::JsonParser& parser) + { + JsonNumberSerializer::ParseFloat(t.Number, parser); + } + + static inline void Format(const JsonNumberObject& t, Detail::JsonFormatter& formatter) + { + JsonNumberSerializer::FormatFloat(t.Number, formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonBooleanObject& t, Detail::JsonParser& parser) + { + JsonBooleanSerializer::ParseBool(t.Boolean, parser); + } + + static inline void Format(const JsonBooleanObject& t, Detail::JsonFormatter& formatter) + { + JsonBooleanSerializer::FormatBool(t.Boolean, formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonNullObject&, Detail::JsonParser& parser) + { + JsonNullSerializer::ParseNull(parser); + } + + static inline void Format(const JsonNullObject&, Detail::JsonFormatter& formatter) + { + JsonNullSerializer::FormatNull(formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonStructObject& t, Detail::JsonParser& parser) { + parser.Parse(t.Objects); + } + static inline void Format(const JsonStructObject& t, Detail::JsonFormatter& formatter) { + if (formatter.Settings().OrderedStruct == false) + { + formatter.Format(t.Objects); + return; + } + + std::map objectsOrdered; + for (auto& [name, objects] : t.Objects) + objectsOrdered.insert({ name, objects.get()}); + formatter.Format(objectsOrdered); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(JsonArrayObject& t, Detail::JsonParser& parser) { + parser.Parse(t.Objects); + } + static inline void Format(const JsonArrayObject& t, Detail::JsonFormatter& formatter) { + formatter.Format(t.Objects); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/STDSerializers/BasicSTDSerializers.h b/src/ProjectCore/Json/Serializers/STDSerializers/BasicSTDSerializers.h new file mode 100644 index 0000000..100437e --- /dev/null +++ b/src/ProjectCore/Json/Serializers/STDSerializers/BasicSTDSerializers.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ProjectCore/Json/JsonSerializer.h" + +#include + +namespace ProjectCore::JSON +{ + template <> + struct JsonSerializer + { + static inline void Parse(std::string& t, Detail::JsonParser& parser) { + JsonStringSerializer::ParseSTDString(t, parser); + } + static inline void Format(const std::string& t, Detail::JsonFormatter& formatter) { + JsonStringSerializer::FormatSTDString(t, formatter); + } + }; + + template <> + struct JsonSerializer + { + static inline void Parse(std::string_view& t, Detail::JsonParser& parser) { + // TODO: + } + static inline void Format(const std::string_view& t, Detail::JsonFormatter& formatter) { + JsonStringSerializer::FormatSTDString(t, formatter); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/STDSerializers/JSON_map.h b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_map.h new file mode 100644 index 0000000..6dc0811 --- /dev/null +++ b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_map.h @@ -0,0 +1,52 @@ +#pragma once + +#include "ProjectCore/Json/JsonSerializer.h" + +#include + +namespace ProjectCore::JSON +{ + template + struct JsonSerializer> + { + using KeyType = K; + using StructSubObjectType = T; + + static inline void Parse(std::map& t, Detail::JsonParser& parser) { + JsonStructSerializer::LoadAllSubObjects>(t, parser); + } + static inline void AddStructSubObject(std::map& t, std::size_t, std::string&& name, StructSubObjectType&& subObject) { + t.insert({std::move(name), std::move(subObject)}); + } + + static inline void Format(const std::map& t, Detail::JsonFormatter& formatter) { + JsonStructSerializer::FormatBegin(formatter); + std::size_t idx = 0; + for (const auto& [name, object] : t) + JsonStructSerializer::FormatObject(name, object, idx++, formatter); + JsonStructSerializer::FormatEnd(formatter); + } + }; + + template + struct JsonSerializer> + { + using KeyType = K; + using StructSubObjectType = T; + + static inline void Parse(std::multimap& t, Detail::JsonParser& parser) { + JsonStructSerializer::LoadAllSubObjects>(t, parser); + } + static inline void AddStructSubObject(std::multimap& t, std::size_t, std::string&& name, StructSubObjectType&& subObject) { + t.insert({std::move(name), std::move(subObject)}); + } + + static inline void Format(const std::multimap& t, Detail::JsonFormatter& formatter) { + JsonStructSerializer::FormatBegin(formatter); + std::size_t idx = 0; + for (const auto& [name, object] : t) + JsonStructSerializer::FormatObject(name, object, idx++, formatter); + JsonStructSerializer::FormatEnd(formatter); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/STDSerializers/JSON_unordered_map.h b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_unordered_map.h new file mode 100644 index 0000000..a90b70a --- /dev/null +++ b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_unordered_map.h @@ -0,0 +1,53 @@ +#pragma once + +#include "ProjectCore/Json/JsonObjects.h" +#include "ProjectCore/Json/JsonSerializer.h" + +#include + +namespace ProjectCore::JSON +{ + template + struct JsonSerializer> + { + using KeyType = K; + using StructSubObjectType = T; + + static inline void Parse(std::unordered_map& t, Detail::JsonParser& parser) { + JsonStructSerializer::LoadAllSubObjects>(t, parser); + } + static inline void AddStructSubObject(std::unordered_map& t, std::size_t, std::string&& name, StructSubObjectType&& subObject) { + t.insert({std::move(name), std::move(subObject)}); + } + + static inline void Format(const std::unordered_map& t, Detail::JsonFormatter& formatter) { + JsonStructSerializer::FormatBegin(formatter); + std::size_t idx = 0; + for (const auto& [name, object] : t) + JsonStructSerializer::FormatObject(name, object, idx++, formatter); + JsonStructSerializer::FormatEnd(formatter); + } + }; + + template + struct JsonSerializer> + { + using KeyType = K; + using StructSubObjectType = T; + + static inline void Parse(std::unordered_multimap& t, Detail::JsonParser& parser) { + JsonStructSerializer::LoadAllSubObjects>(t, parser); + } + static inline void AddStructSubObject(std::unordered_multimap& t, std::size_t, std::string&& name, StructSubObjectType&& subObject) { + t.insert({std::move(name), std::move(subObject)}); + } + + static inline void Format(const std::unordered_multimap& t, Detail::JsonFormatter& formatter) { + JsonStructSerializer::FormatBegin(formatter); + std::size_t idx = 0; + for (const auto& [name, object] : t) + JsonStructSerializer::FormatObject(name, object, idx++, formatter); + JsonStructSerializer::FormatEnd(formatter); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/STDSerializers/JSON_vector.h b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_vector.h new file mode 100644 index 0000000..dc3b609 --- /dev/null +++ b/src/ProjectCore/Json/Serializers/STDSerializers/JSON_vector.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ProjectCore/Json/JsonObjects.h" +#include "ProjectCore/Json/JsonSerializer.h" + +#include + +namespace ProjectCore::JSON +{ + template + struct JsonSerializer> + { + using ArraySubObjectType = T; + + static inline void Parse(std::vector& t, Detail::JsonParser& parser) { + JsonArraySerializer::LoadAllSubObjects>(t, parser); + } + static inline void AddArraySubObject(std::vector& t, std::size_t, ArraySubObjectType&& subObject) { + t.emplace_back(std::move(subObject)); + } + + static inline void Format(const std::vector& t, Detail::JsonFormatter& formatter) { + JsonArraySerializer::FormatBegin(formatter); + std::size_t idx = 0; + for (const ArraySubObjectType& subObject : t) + JsonArraySerializer::FormatObject(subObject, idx++, formatter); + JsonArraySerializer::FormatEnd(formatter); + } + }; +} diff --git a/src/ProjectCore/Json/Serializers/Serializers.h b/src/ProjectCore/Json/Serializers/Serializers.h new file mode 100644 index 0000000..619981f --- /dev/null +++ b/src/ProjectCore/Json/Serializers/Serializers.h @@ -0,0 +1,5 @@ +#pragma once + +#include "BaseSerializers.h" +#include "JsonObjectsSerializer.h" +#include "STDSerializers/BasicSTDSerializers.h" diff --git a/src/ProjectCore/LoggerManager/Detail/Detail.h b/src/ProjectCore/LoggerManager/Detail/Detail.h new file mode 100644 index 0000000..997184b --- /dev/null +++ b/src/ProjectCore/LoggerManager/Detail/Detail.h @@ -0,0 +1,46 @@ +#pragma once + +#include "ProjectCore/FMT/FMT.h" + +namespace ProjectCore::LoggerManager +{ + template + struct AddIndentInFormat + { + AddIndentInFormat(const FormatStr& format) + : Format(format) + {} + const FormatStr& Format; + }; + + template + struct ConcateNameAndSinkName + { + ConcateNameAndSinkName(const std::basic_string& loggerName, const std::basic_string& sinkName) + : LoggerName(loggerName) + , SinkName(sinkName) + {} + const std::basic_string& LoggerName; + const std::basic_string& SinkName; + }; +} + +namespace ProjectCore::FMT +{ + template + struct FormatterType, FormatterContext> + { + static void Format(const ProjectCore::LoggerManager::AddIndentInFormat& format, FormatterContext& context) { + context.BufferOut().FastWriteCharArray("{K:indent}"); + context.RunType(format.Format); + } + }; + + template + struct FormatterType, FormatterContext> + { + static void Format(const ProjectCore::LoggerManager::ConcateNameAndSinkName& names, FormatterContext& context) { + context.SubContext(names.LoggerName, FORMAT_SV("sink", names.SinkName)); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h b/src/ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h new file mode 100644 index 0000000..4b039b4 --- /dev/null +++ b/src/ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Detail.h" +#include "LoggerSink.h" +#include "ProjectCore/LoggerManager/Loggers/BasicLogger.h" + +namespace ProjectCore::LoggerManager::Detail +{ + template + class BasicLoggerMultiSinkImpl + { + public: + using SinkType = BasicLoggerSink; + using SeverityValueType = typename Severity::Value; + + public: + BasicLoggerMultiSinkImpl() : m_Name("Logger:{sink}") {} + BasicLoggerMultiSinkImpl(std::basic_string&& name) : m_Name(std::forward>(name)) {} + virtual ~BasicLoggerMultiSinkImpl() = default; + + public: + void SetName(std::basic_string&& name) { m_Name = std::forward>(name); } + + std::basic_string& GetName() { return m_Name; } + std::vector>& GetSinks() { return m_Sinks; } + + protected: + std::basic_string m_Name; + std::vector> m_Sinks; + + public: + void AddSink(std::shared_ptr sink) + { + m_Sinks.push_back(sink); + } + + template + void EmplaceSink(Args&&... args) + { + std::shared_ptr sink = std::make_shared(std::forward(args)...); + AddSink(sink); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/Detail/LoggerSink.h b/src/ProjectCore/LoggerManager/Detail/LoggerSink.h new file mode 100644 index 0000000..287d18a --- /dev/null +++ b/src/ProjectCore/LoggerManager/Detail/LoggerSink.h @@ -0,0 +1,108 @@ +#pragma once + +#include "Detail.h" +#include + +namespace ProjectCore::LoggerManager::Detail +{ + enum class AsyncSink + { + Sync, + Async + }; + + template + class BasicLoggerSink + { + public: + using PatternType = std::basic_string; + using PatternTransfertType = std::basic_string_view; + using NameType = std::basic_string; + using BufferType = std::basic_string_view; + + using SeverityValueType = typename Severity::Value; + + public: + BasicLoggerSink(NameType&& name) + : Name(std::forward(name)) + , IsAsync(AsyncSink::Sync) + {} + + BasicLoggerSink(NameType&& name, AsyncSink isAsync) + : Name(std::forward(name)) + , IsAsync(isAsync) + {} + + virtual ~BasicLoggerSink() = default; + + public: + NameType Name = ""; + PatternType Pattern = "{name} >> {data}"; + SeverityValueType SinkSeverity{SeverityValueType::DefaultSeverity}; + typename Severity::PatternOverride SeverityPatternOverride; + AsyncSink IsAsync; + + protected: + std::future m_AsyncWaiter; + + public: + bool NeedToLog(const SeverityValueType& severity) { return severity >= SinkSeverity; } + void WriteToSink(const SeverityValueType& severity, const BufferType& bufferToPrint) { if (NeedToLog(severity)) WriteToSink(bufferToPrint); } + + public: + PatternTransfertType GetPattern(const typename Severity::Value& severity) const + { + PatternTransfertType customPattern = SeverityPatternOverride.GetPattern(severity); + if (customPattern.data() == nullptr || customPattern.size() == 0) + return Pattern; + return customPattern; + } + + protected: + virtual void WriteImpl(const BufferType& bufferToPrint) = 0; + + public: + void WriteToSinkSync(const BufferType& bufferToPrint) { WriteImpl(bufferToPrint); } + void WriteToSinkAsync(const BufferType& bufferToPrint) + { + m_AsyncWaiter = std::async(std::launch::async, &BasicLoggerSink::WriteToSinkSync, this, bufferToPrint); + } + + void WriteToSink(const BufferType& bufferToPrint) + { + if (IsAsync == AsyncSink::Sync) + WriteToSinkSync(bufferToPrint); + else + WriteToSinkAsync(bufferToPrint); + } + + public: + void WaitUnitlFinishedToWrite() + { + if (IsAsync == AsyncSink::Async) + return m_AsyncWaiter.get(); + } + + void FormatAndWriteToSinkSync(PatternTransfertType pattern, const NameType& loggerName, const BufferType& formatBuffer) + { + auto formatPatternStr = FMT::Detail::FormatAndGetBufferOut(pattern, + FORMAT_SV("name", ConcateNameAndSinkName(loggerName, Name)), + FORMAT_SV("data", formatBuffer)); + BufferType buffer(*formatPatternStr); + WriteToSinkSync(buffer); + } + + void FormatAndWriteToSinkAsync(PatternTransfertType pattern, const NameType& loggerName, const BufferType& formatBuffer) + { + m_AsyncWaiter = std::async(std::launch::async, &BasicLoggerSink::FormatAndWriteToSinkSync, this, pattern, loggerName, formatBuffer); + } + + void FormatAndWriteToSink(PatternTransfertType pattern, const NameType& loggerName, const BufferType& formatBuffer) + { + if (IsAsync == AsyncSink::Sync) + FormatAndWriteToSinkSync(pattern, loggerName, formatBuffer); + else + FormatAndWriteToSinkAsync(pattern, loggerName, formatBuffer); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/LoggerFactory.h b/src/ProjectCore/LoggerManager/LoggerFactory.h new file mode 100644 index 0000000..d2473b5 --- /dev/null +++ b/src/ProjectCore/LoggerManager/LoggerFactory.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Loggers/BasicLogger.h" +#include "Loggers/LoggerMultiSinkFast.h" +#include "Loggers/LoggerMultiSinkSafe.h" + +namespace ProjectCore::LoggerManager +{ + class LoggerFactory + { + + }; +} diff --git a/src/ProjectCore/LoggerManager/LoggerImpl/XLogger.h b/src/ProjectCore/LoggerManager/LoggerImpl/XLogger.h new file mode 100644 index 0000000..bdf7fcf --- /dev/null +++ b/src/ProjectCore/LoggerManager/LoggerImpl/XLogger.h @@ -0,0 +1,169 @@ +#pragma once + +#include "ProjectCore/LoggerManager/Detail/Detail.h" +#include "ProjectCore/LoggerManager/Loggers/BasicLogger.h" +#include "ProjectCore/LoggerManager/Loggers/LoggerMultiSinkFast.h" +#include "ProjectCore/LoggerManager/Loggers/LoggerMultiSinkSafe.h" +#include "ProjectCore/LoggerManager/Sinks/FileSink.h" + +namespace ProjectCore::LoggerManager +{ + struct LogSeverity + { + public: + enum class Value : int + { + Trace, + Debug, + Info, + Warn, + Error, + Fatal, + DefaultSeverity = Trace + }; + + public: + static constexpr Value Trace {Value::Trace}; + static constexpr Value Debug {Value::Debug}; + static constexpr Value Info {Value::Info}; + static constexpr Value Warn {Value::Warn}; + static constexpr Value Error {Value::Error}; + static constexpr Value Fatal {Value::Fatal}; + static constexpr Value DefaultSeverity = Trace; + + public: + class PatternOverride + { + public: + std::basic_string TracePattern = ""; + std::basic_string DebugPattern = ""; + std::basic_string InfoPattern = ""; + std::basic_string WarnPattern = ""; + std::basic_string ErrorPattern = ""; + std::basic_string FatalPattern = ""; + + std::basic_string_view GetPattern(const Value& severity) const + { + switch(severity) + { + case Value::Trace: if (TracePattern.empty() == false) return TracePattern; break; + case Value::Debug: if (DebugPattern.empty() == false) return DebugPattern; break; + case Value::Info: if (InfoPattern.empty() == false) return InfoPattern; break; + case Value::Warn: if (WarnPattern.empty() == false) return WarnPattern; break; + case Value::Error: if (ErrorPattern.empty() == false) return ErrorPattern; break; + case Value::Fatal: if (FatalPattern.empty() == false) return FatalPattern; break; + } + return std::basic_string_view{nullptr, 0}; + } + }; + }; +} + +namespace ProjectCore::LoggerManager::Detail { + template + class XLogger : public Master + { + public: + template + XLogger(Args&&... args) + : Master(std::forward(args)...) + {} + + ~XLogger() override = default; + + public: + template + requires FMT::Detail::CanBeUseForFMTBufferIn + void Log(Severity status, const Format& format, Args&& ...args) { Master::template Log(status, format, std::forward(args)...); } + + template + void Log(Severity status, T&& t) { Master::template Log(status, std::forward(t)); } + + public: + /////---------- Logger Severity with array as format ----------///// + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Trace(const Format& format, Args&& ...args) { return Log(LogSeverity::Trace, format, std::forward(args)...); } + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Debug(const Format& format, Args&& ...args) { return Log(LogSeverity::Debug, format, std::forward(args)...); } + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Info(const Format& format, Args&& ...args) { return Log(LogSeverity::Info, format, std::forward(args)...); } + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Warn(const Format& format, Args&& ...args) { return Log(LogSeverity::Warn, format, std::forward(args)...); } + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Error(const Format& format, Args&& ...args) { return Log(LogSeverity::Error, format, std::forward(args)...); } + template + requires FMT::Detail::CanBeUseForFMTBufferIn + inline void Fatal(const Format& format, Args&& ...args) { return Log(LogSeverity::Fatal, format, std::forward(args)...); } + + /////---------- NO-FORMAT Logger Severity ----------///// + template + inline void Trace(T&& t) { return Log(LogSeverity::Trace, std::forward(t)); } + template + inline void Debug(T&& t) { return Log(LogSeverity::Debug, std::forward(t)); } + template + inline void Info(T&& t) { return Log(LogSeverity::Info, std::forward(t)); } + template + inline void Warn(T&& t) { return Log(LogSeverity::Warn, std::forward(t)); } + template + inline void Error(T&& t) { return Log(LogSeverity::Error, std::forward(t)); } + template + inline void Fatal(T&& t) { return Log(LogSeverity::Fatal, std::forward(t)); } + }; +} + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const ProjectCore::LoggerManager::LogSeverity::Value t, FormatterContext& context) + { + context.GetFormatData().KeepNewStyle = true; + switch (t) + { + case ProjectCore::LoggerManager::LogSeverity::Trace: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::BrightBlack, context); + break; + case ProjectCore::LoggerManager::LogSeverity::Debug: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::Blue, context); + break; + case ProjectCore::LoggerManager::LogSeverity::Info: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::Green, context); + break; + case ProjectCore::LoggerManager::LogSeverity::Warn: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::Yellow, context); + break; + case ProjectCore::LoggerManager::LogSeverity::Error: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::Red, context); + break; + case ProjectCore::LoggerManager::LogSeverity::Fatal: + FormatterType::Format(Detail::TextProperties::TextColor::BasicColorFG::BrightMagenta, context); + break; + } + } + }; +} + +namespace ProjectCore::LoggerManager +{ + template + using BasicLoggerMultiSinkFast = Detail::XLogger>; + using LoggerMultiSinkFast = BasicLoggerMultiSinkFast; + + template + using BasicLoggerMultiSinkSafe = Detail::XLogger>; + using LoggerMultiSinkSafe = BasicLoggerMultiSinkSafe; + + using BasicLogger = Detail::XLogger>; +} + +namespace ProjectCore::LoggerManager::Sinks +{ + using ConsoleSink = Severity::ConsoleSink; + using FileSink = Severity::FileSink; +} diff --git a/src/ProjectCore/LoggerManager/LoggerManager.h b/src/ProjectCore/LoggerManager/LoggerManager.h new file mode 100644 index 0000000..b15d6cf --- /dev/null +++ b/src/ProjectCore/LoggerManager/LoggerManager.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Loggers/BasicLogger.h" +#include "Loggers/LoggerMultiSinkFast.h" +#include "Loggers/LoggerMultiSinkSafe.h" + +#include "Sinks/FileSink.h" + +#include "LoggerImpl/XLogger.h" + +#include "LoggerFactory.h" diff --git a/src/ProjectCore/LoggerManager/Loggers/BasicLogger.h b/src/ProjectCore/LoggerManager/Loggers/BasicLogger.h new file mode 100644 index 0000000..7afe745 --- /dev/null +++ b/src/ProjectCore/LoggerManager/Loggers/BasicLogger.h @@ -0,0 +1,80 @@ +#pragma once + +#include "ProjectCore/LoggerManager/Detail/Detail.h" + +#include + +namespace ProjectCore::LoggerManager::Detail +{ + template + class BasicLoggerImpl + { + public: + using SeverityValueType = typename Severity::Value; + + public: + BasicLoggerImpl() : m_Name("Logger"), m_Severity(Severity::Value::DefaultSeverity), m_Stream(std::cout) { ResetPattern(); } + + explicit BasicLoggerImpl(const std::string_view& name, typename Severity::Value severity = Severity::Value::DefaultSeverity, std::ostream& stream = std::cout) + : m_Name(name), m_Severity(severity), m_Stream(stream) + , preFormatBufferOutManager(64) + , fullFormatBufferOutManager(64) + { + ResetPattern(); + } + explicit BasicLoggerImpl(const std::string_view& name, const std::string_view& format, typename Severity::Value severity = Severity::Value::DefaultSeverity, std::ostream& stream = std::cout) + : m_Name(name), m_Severity(severity), m_Stream(stream) + , preFormatBufferOutManager(64) + , fullFormatBufferOutManager(64) + { + SetPattern(format); + } + + virtual ~BasicLoggerImpl() = default; + + public: + void SetSeverity(const SeverityValueType& severity) { m_Severity = severity; } + void SetName(const std::string& name) { m_Name = name; } + void SetName(std::string&& name) { m_Name = std::move(name); } + void SetRealPattern(std::string_view pattern) { m_Pattern = pattern; } + void SetRealPatternStrmv(std::string&& pattern) { m_Pattern = std::move(pattern); } + void SetPattern(std::string_view pattern) { m_Pattern = "{color}"; m_Pattern += pattern; } + void ResetPattern() { SetPattern("[{T:pattern='%h:%m:%s:%ms'}] {name} >> {data}"); } + + private: + std::string m_Name; + SeverityValueType m_Severity; + std::ostream& m_Stream; + std::string m_Pattern; + FMT::Detail::DynamicBufferOutManager preFormatBufferOutManager; + FMT::Detail::DynamicBufferOutManager fullFormatBufferOutManager; + + public: + template + requires FMT::Detail::CanBeUseForFMTBufferIn + void Log(const SeverityValueType& severity, const Format& format, Args&& ...args) + { + if (severity < m_Severity) + return; + + FMT::Detail::BufferInProperties preFormatBufferInProperties(m_Pattern); + FMT::Detail::FormatInBufferOutManager(preFormatBufferOutManager, preFormatBufferInProperties, false, FORMAT_SV("name", m_Name), FORMAT_SV("data", LoggerManager::AddIndentInFormat(format))); + FMT::Detail::BufferInProperties fullFormatBufferInProperties(preFormatBufferOutManager.GetLastGeneratedStringView()); + FMT::Detail::FormatInBufferOutManager(fullFormatBufferOutManager, fullFormatBufferInProperties, true, std::forward(args)..., FORMAT_SV("color", severity)); + m_Stream.write(fullFormatBufferOutManager.GetBuffer(), static_cast(fullFormatBufferOutManager.GetLastGeneratedDataSize())); + m_Stream.flush(); + } + + template + void Log(const SeverityValueType& severity, T&& t) + { + if (severity < m_Severity) + return; + + FMT::Detail::BufferInProperties fullFormatBufferInProperties(m_Pattern); + FMT::Detail::FormatInBufferOutManager(fullFormatBufferOutManager, fullFormatBufferInProperties, true, FORMAT_SV("data", t), FORMAT_SV("color", severity), FORMAT_SV("name", m_Name)); + m_Stream.write(fullFormatBufferOutManager.GetBuffer(), static_cast(fullFormatBufferOutManager.GetLastGeneratedDataSize())); + m_Stream.flush(); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/Loggers/BasicLoggerMacro.h b/src/ProjectCore/LoggerManager/Loggers/BasicLoggerMacro.h new file mode 100644 index 0000000..cad574c --- /dev/null +++ b/src/ProjectCore/LoggerManager/Loggers/BasicLoggerMacro.h @@ -0,0 +1,28 @@ +#pragma once + +#include "BasicLogger.h" + +#ifndef PROJECTCORE_BASE_LOGGER_NAME + #define PROJECTCORE_BASE_LOGGER_NAME "APP" +#endif + +namespace ProjectCore::LoggerManager +{ + [[maybe_unused]] static BasicLogger& GetLoggerCore() { static BasicLogger instance(PROJECTCORE_BASE_LOGGER_NAME "-Core", LogSeverity::Trace); return instance; } + [[maybe_unused]] static BasicLogger& GetLoggerClient() { static BasicLogger instance(PROJECTCORE_BASE_LOGGER_NAME "-Client", LogSeverity::Trace); return instance; } +} + + +#ifdef PROJECTCORE_LOGGER_ENABLE + #define PROJECTCORE_TRACE(...) ProjectCore::LoggerManager::BasicLogger::GetCoreInstance().Trace(__VA_ARGS__) + #define PROJECTCORE_INFO(...) ProjectCore::LoggerManager::BasicLogger::GetCoreInstance().Info(__VA_ARGS__) + #define PROJECTCORE_WARN(...) ProjectCore::LoggerManager::BasicLogger::GetCoreInstance().Warn(__VA_ARGS__) + #define PROJECTCORE_ERROR(...) ProjectCore::LoggerManager::BasicLogger::GetCoreInstance().Error(__VA_ARGS__) + #define PROJECTCORE_FATAL(...) ProjectCore::LoggerManager::BasicLogger::GetCoreInstance().Fatal(__VA_ARGS__) +#else + #define PROJECTCORE_TRACE(...) + #define PROJECTCORE_INFO(...) + #define PROJECTCORE_WARN(...) + #define PROJECTCORE_ERROR(...) + #define PROJECTCORE_FATAL(...) +#endif diff --git a/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkFast.h b/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkFast.h new file mode 100644 index 0000000..962b259 --- /dev/null +++ b/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkFast.h @@ -0,0 +1,56 @@ +#pragma once + +#include "ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h" + +namespace ProjectCore::LoggerManager::Detail +{ + template + class BasicLoggerMultiSinkFastImpl : public BasicLoggerMultiSinkImpl + { + public: + using Base = BasicLoggerMultiSinkImpl; + using Base::SetName; + using Base::GetName; + using Base::GetSinks; + using Base::m_Name; + using Base::m_Sinks; + using Base::AddSink; + + using typename Base::SeverityValueType; + + public: + BasicLoggerMultiSinkFastImpl() : Base() {} + + BasicLoggerMultiSinkFastImpl(std::basic_string&& name) + : Base(std::forward>(name)) + {} + + ~BasicLoggerMultiSinkFastImpl() override = default; + + public: + template + requires FMT::Detail::CanBeUseForFMTBufferIn + void Log(const SeverityValueType& severity, const Format& format, Args&& ...args) { + auto formatBuffer = FMT::Detail::FormatAndGetBufferOut(format, std::forward(args)...); + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->FormatAndWriteToSink(sink->GetPattern(severity), m_Name, static_cast>(*formatBuffer)); + + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->WaitUnitlFinishedToWrite(); + } + + template + void Log(const SeverityValueType& severity, T&& t) { + auto formatBuffer = FMT::Detail::FormatAndGetBufferOut(std::forward(t)); + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->FormatAndWriteToSink(sink->GetPattern(severity), m_Name, static_cast>(*formatBuffer)); + + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->WaitUnitlFinishedToWrite(); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkSafe.h b/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkSafe.h new file mode 100644 index 0000000..a365b94 --- /dev/null +++ b/src/ProjectCore/LoggerManager/Loggers/LoggerMultiSinkSafe.h @@ -0,0 +1,65 @@ +#pragma once + +#include "ProjectCore/LoggerManager/Detail/LoggerMultiSinks.h" + +namespace ProjectCore::LoggerManager::Detail +{ + template + class BasicLoggerMultiSinkSafeImpl: public BasicLoggerMultiSinkImpl + { + public: + using Base = BasicLoggerMultiSinkImpl; + using Base::SetName; + using Base::GetName; + using Base::GetSinks; + using Base::m_Name; + using Base::m_Sinks; + using Base::AddSink; + using typename Base::SeverityValueType; + + public: + BasicLoggerMultiSinkSafeImpl() : Base() {} + + BasicLoggerMultiSinkSafeImpl(std::basic_string&& name) + : Base(std::forward>(name)) + {} + + ~BasicLoggerMultiSinkSafeImpl() override = default; + + public: + template + requires FMT::Detail::CanBeUseForFMTBufferIn + void Log(const SeverityValueType& severity, const Format& format, Args&& ...args) { + // FIXME maybe add : name ; indent ??? + for (auto& sink : m_Sinks) + { + if (sink->NeedToLog(severity)) + { + auto formatPatternStr = FMT::Detail::FormatAndGetBufferOut(std::string_view(sink->GetPattern(severity)), FORMAT_SV("name", m_Name), FORMAT_SV("data", LoggerManager::AddIndentInFormat(format))); + auto formatFormatStr = FMT::Detail::FormatAndGetBufferOut(static_cast(*formatPatternStr), std::forward(args)..., FORMAT_SV("sink", sink->GetName()), FORMAT_SV("color", severity)); + sink->WriteToSink(static_cast>(*formatFormatStr)); + } + } + + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->WaitUnitlFinishedToWrite(); + } + + template + void Log(const SeverityValueType& severity, T&& t) { + for (auto& sink : m_Sinks) + { + if (sink->NeedToLog(severity)) + { + auto formatBuffer = FMT::Detail::FormatAndGetBufferOut(std::string_view(sink->GetPattern(severity)), FORMAT_SV("name", ConcateNameAndSinkName(m_Name, sink->GetName())), FORMAT_SV("data", t)); + sink->WriteToSink(static_cast>(*formatBuffer)); + } + } + + for (auto& sink : m_Sinks) + if (sink->NeedToLog(severity)) + sink->WaitUnitlFinishedToWrite(); + } + }; +} diff --git a/src/ProjectCore/LoggerManager/Sinks/FileSink.h b/src/ProjectCore/LoggerManager/Sinks/FileSink.h new file mode 100644 index 0000000..7f8f428 --- /dev/null +++ b/src/ProjectCore/LoggerManager/Sinks/FileSink.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include + +#include "ProjectCore/LoggerManager/Detail/LoggerSink.h" + +namespace ProjectCore::LoggerManager::Sinks +{ + template + class BasicConsoleSink : public Detail::BasicLoggerSink + { + public: + using Base = Detail::BasicLoggerSink; + using typename Base::PatternType; + using typename Base::NameType; + using typename Base::BufferType; + + public: + BasicConsoleSink(std::basic_ostream& stream, NameType&& name) + : Base(std::forward(name)) + , m_Stream(stream) + {} + + BasicConsoleSink(std::basic_ostream& stream, NameType&& name, Detail::AsyncSink isAsync) + : Base(std::forward(name), isAsync) + , m_Stream(stream) + {} + + ~BasicConsoleSink() override = default; + + public: + std::basic_ostream& GetStream() { return m_Stream; } + + protected: + void WriteImpl(const BufferType& bufferToPrint) override + { + m_Stream.write(bufferToPrint.data(), bufferToPrint.size()); + m_Stream.write("\n", 1); + m_Stream.flush(); + } + + private: + std::basic_ostream& m_Stream; + }; + + template + class BasicFileSink : public Detail::BasicLoggerSink + { + public: + using Base = Detail::BasicLoggerSink; + using typename Base::PatternType; + using typename Base::NameType; + using typename Base::BufferType; + + public: + BasicFileSink(const std::filesystem::path& filePath, NameType&& name, Detail::AsyncSink isAsync) + : Base(std::forward(name), isAsync) + , m_Stream(filePath, std::ios::out) + {} + + ~BasicFileSink() override = default; + + public: + std::basic_ostream& GetStream() { return m_Stream; } + + protected: + void WriteImpl(const BufferType& bufferToPrint) override + { + m_Stream.write(bufferToPrint.data(), bufferToPrint.size()); + m_Stream.write("\n", 1); + m_Stream.flush(); + } + + private: + std::basic_ofstream m_Stream; + }; +} + +namespace ProjectCore::LoggerManager::Sinks::Severity +{ + template + using ConsoleSink = BasicConsoleSink; + template + using FileSink = BasicFileSink; +} diff --git a/src/ProjectCore/Tester/TestSuite/AllTestSuite.h b/src/ProjectCore/Tester/TestSuite/AllTestSuite.h new file mode 100644 index 0000000..b078801 --- /dev/null +++ b/src/ProjectCore/Tester/TestSuite/AllTestSuite.h @@ -0,0 +1,2 @@ +#include "TestSuite.h" +#include "BasicTest.h" diff --git a/src/ProjectCore/Tester/TestSuite/BasicTest.h b/src/ProjectCore/Tester/TestSuite/BasicTest.h new file mode 100644 index 0000000..2bebd5a --- /dev/null +++ b/src/ProjectCore/Tester/TestSuite/BasicTest.h @@ -0,0 +1,91 @@ +#pragma once + +#include "TestSuite.h" + +#include "ProjectCore/FMT/Format/CompilationData.h" + +namespace ProjectCore::Tester::Detail +{ + struct TestFunction : public Test + { + public: + using FuncType = std::function; + + public: + TestFunction(std::string&& name, TestSuite& link, FuncType func, const FMT::Detail::FileLocation& location) + : Test(std::move(name), link, location) + , Func(func) + { + Link.Tests.insert({Name, this}); + } + + ~TestFunction() override = default; + + protected: + TestStatus RunImpl() override + { + Func(*this); + return TestStatus::Ok; + } + + public: + void TestAssert(bool assert, const std::string_view assertView, int line); + template + void TestEq(T result, std::convertible_to auto expected, std::string_view testView, int line); + template + void TestNotEq(T result, std::convertible_to auto notExpected, std::string_view testView, int line); + + public: + FuncType Func; + }; + + + template + void TestFunction::TestEq(T result, std::convertible_to auto expected, std::string_view testView, [[maybe_unused]] int line) + { + if (result != static_cast(expected)) + { + Link.TestLogger.Error("{C:red}{} return {} instead of {}", testView, result, expected, FORMAT_SV("test_name", Name)); + throw TestFailure{}; + } + + Link.TestLogger.Trace("{C:green}{} return {}", testView, result, FORMAT_SV("test_name", Name)); + } + + template + void TestFunction::TestNotEq(T result, std::convertible_to auto notExpected, std::string_view testView, [[maybe_unused]] int line) + { + if (result == static_cast(notExpected)) + { + Link.TestLogger.Error("{C:red}{} return {} but this result was prohibited", testView, result, FORMAT_SV("test_name", Name)); + throw TestFailure{}; + } + + Link.TestLogger.Trace("{C:green}{} return {}", testView, result, FORMAT_SV("test_name", Name)); + } + + inline void TestFunction::TestAssert(bool assert, std::string_view assertView, [[maybe_unused]] int line) + { + if (assert == false) + { + Link.TestLogger.Error("{C:red}ASSERT FAILED : {}", assertView, FORMAT_SV("test_name", Name)); + throw TestFailure{}; + } + + Link.TestLogger.Trace("{C:green}ASSERT SUCCED : {}", assertView, FORMAT_SV("test_name", Name)); + } +} + + +#define PROJECTCORE_TESTINTERNAL_FUNC_DECLARE_EXEC(TestSuiteName, TestName) void PROJECTCORE_TESTINTERNAL_FUNC_EXEC_NAME(TestSuiteName, TestName)(ProjectCore::Tester::Detail::TestFunction &link); +#define PROJECTCORE_TESTINTERNAL_FUNC_CREATE(TestSuiteName, TestName, ...) volatile ProjectCore::Tester::Detail::TestFunction PROJECTCORE_TESTINTERNAL_FUNC_NAME(TestSuiteName, TestName)(#TestName, PROJECTCORE_TESTINTERNAL_SUITE_NAME(TestSuiteName), PROJECTCORE_TESTINTERNAL_FUNC_EXEC_NAME(TestSuiteName, TestName), PROJECTCORE_FMT_FILE_LOCATION()) + +#define PCT_TEST_FUNC(TestSuiteName, TestName) PROJECTCORE_TESTINTERNAL_FUNC_DECLARE_EXEC(TestSuiteName, TestName) \ + PROJECTCORE_TESTINTERNAL_FUNC_CREATE(TestSuiteName, TestName); \ + void PROJECTCORE_TESTINTERNAL_FUNC_EXEC_NAME(TestSuiteName, TestName)(ProjectCore::Tester::Detail::TestFunction &link) + + +#define PCT_ASSERT(Test) link.TestAssert(Test, #Test, __LINE__) +#define PCT_EQ(Test, Expected) link.TestEq(Test, Expected, #Test, __LINE__) +#define PCT_NEQ(Test, NotExpected) link.TestNotEq(Test, NotExpected, #Test, __LINE__) + diff --git a/src/ProjectCore/Tester/TestSuite/TestSuite.cpp b/src/ProjectCore/Tester/TestSuite/TestSuite.cpp new file mode 100644 index 0000000..e67054e --- /dev/null +++ b/src/ProjectCore/Tester/TestSuite/TestSuite.cpp @@ -0,0 +1,163 @@ +#include "TestSuite.h" +#include "ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h" + +namespace ProjectCore::Tester +{ + bool TestSuitesManager::ExecAllTestSuites() + { + PROJECTCORE_FORMATTER_TIME_BEGIN(); + Detail::TestStatusBank status; + + for (auto& [name, testSuite] : TestSuites) + status.Add(testSuite->ExecAllTests()); + + LoggerManager::BasicLogger logger("TestSuite"); + if (status.IsAllOk()) + logger.Info("{C:white}RESULT => {C:+black}{}", status); + else + logger.Error("{C:white}RESULT => {C:+black}{}", status); + + return status.ErrorStatus(); + } +} + +namespace ProjectCore::Tester::Detail +{ + TestStatusBank TestSuite::ExecAllTests() + { + if (Parent == nullptr) + Profiler = new Instrumentation::Profiler("TestSuite_" + Name); + InitLogger(); + + Instrumentation::Profiler& profiler = GetProfiler(); + Logger.Info("{C:+black}BEGIN"); + Instrumentation::DurationEvent testSuiteDuration(GetFullName(), "Profile"); + testSuiteDuration.Start(); + bool firstTestSuite = true; + TestStatusBank testSuiteStatus; + Instrumentation::DurationEvent testsDuration("Tests", "Profile"); + testsDuration.Start(); + for (auto& [name, test] : Tests) + { + firstTestSuite = false; + Instrumentation::DurationEvent currentTestDuration(test->Name, "Profile"); + TestStatus testStatus = TestStatus::Fail; + currentTestDuration.Start(); + if (TestSuitesManager::PerformanceTest.Enable == false) + testStatus = test->Run(); + else + { + for (std::uint32_t i = 0; i < TestSuitesManager::PerformanceTest.NbSamples; ++i) + { + testStatus = test->Run(); + if (testStatus != TestStatus::Ok) + break; + } + } + currentTestDuration.Stop(); + if (testStatus != TestStatus::Ok) + { + } + testSuiteStatus.AddTestStatus(testStatus); + Logger.Debug("{} -> {}", testStatus, name); + profiler.AddEvent(currentTestDuration); + } + testsDuration.Stop(); + + Instrumentation::DurationEvent groupsDuration("Groups", "Profile"); + groupsDuration.Start(); + for (auto& [name, testSuite] : TestSuitesLinked) + { + if (firstTestSuite) + firstTestSuite = false; + else + std::cout << std::endl; + testSuiteStatus.Add(testSuite->ExecAllTests()); + } + groupsDuration.Stop(); + testSuiteDuration.Stop(); + profiler.AddEvent(testsDuration); + profiler.AddEvent(groupsDuration); + profiler.AddEvent(testSuiteDuration); + + if (testSuiteStatus.IsAllOk()) + Logger.Info("{C:+black}{}", testSuiteStatus); + else + Logger.Error("{C:+black}{}", testSuiteStatus); + + if (Parent == nullptr) + { + Instrumentation::ProfilerFactory::ToJson(*Profiler); + delete Profiler; + } + + return testSuiteStatus; + } + + void TestSuite::InitLogger() + { + if (TestSuitesManager::Verbose == false) + { + Logger.SetSeverity(LoggerManager::LogSeverity::Debug); + TestLogger.SetSeverity(LoggerManager::LogSeverity::Debug); + } + else + { + Logger.SetSeverity(LoggerManager::LogSeverity::Trace); + TestLogger.SetSeverity(LoggerManager::LogSeverity::Trace); + } + + std::string timePattern = ""; + if (TestSuitesManager::PrintTime) + timePattern = "[{T:pattern='%h:%m:%s:%ms'}] "; + + if (Parent == nullptr) + { + Logger.SetName(Name); + Logger.SetRealPattern("{C:+black}" + timePattern + "{name} >> {color}{data}"); + TestLogger.SetName(Name + ".{test_name}"); + TestLogger.SetRealPattern("{C:+black}" + timePattern + "{name} >> {color}{data}"); + } + else + { + std::string correctedName = GetCorrectedSizeName(); + Logger.SetName(correctedName); + Logger.SetRealPatternStrmv("{C:+black}" + timePattern + "{name} >> {color}{data}"); + TestLogger.SetName(correctedName + ".{test_name}"); + TestLogger.SetRealPatternStrmv("{C:+black}" + timePattern + "{name} >> {color}{data}"); + } + } + + std::string TestSuite::GetFullName() + { + if (Parent == nullptr) + return Name; + return Parent->GetFullName() + "::" + Name; + } + + std::string TestSuite::GetCorrectedSizeName() + { + if (Parent == nullptr) + return Name; + std::size_t biggestName = 0; + for (auto& [name, testSuite] : Parent->TestSuitesLinked) + { + std::size_t tmp = testSuite->Name.size(); + if (tmp > biggestName) + biggestName = tmp; + } + std::string res = GetFullName(); + biggestName -= Name.size(); + res.reserve(res.size() + biggestName); + for (std::uint32_t i = 0; i < biggestName; ++i) + res.push_back(' '); + return res; + } + + Instrumentation::Profiler& TestSuite::GetProfiler() + { + if (Parent == nullptr) + return *Profiler; + return Parent->GetProfiler(); + } +} diff --git a/src/ProjectCore/Tester/TestSuite/TestSuite.h b/src/ProjectCore/Tester/TestSuite/TestSuite.h new file mode 100644 index 0000000..5b82943 --- /dev/null +++ b/src/ProjectCore/Tester/TestSuite/TestSuite.h @@ -0,0 +1,256 @@ +#pragma once + +#include "ProjectCore/FMT/FMT.h" +#include "ProjectCore/LoggerManager/LoggerManager.h" +#include "ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h" + +#include +#include +#include + +namespace ProjectCore::Tester +{ + class TestFailure {}; + + enum class TestStatus : int + { + Ok, + Fail, + Crash + }; +} + +namespace ProjectCore::Tester::Detail +{ + class TestSuite; + class Test + { + public: + Test(std::string&& name, TestSuite& link, const FMT::Detail::FileLocation& location) + : Name(std::move(name)) + , Link(link) + , Location(location) + , LastStatus(TestStatus::Ok) + {} + + virtual ~Test() = default; + + protected: + virtual TestStatus RunImpl() = 0; + + public: + TestStatus Run() + { + try + { + return LastStatus = RunImpl(); + } + catch (const TestFailure&) + { + return LastStatus = TestStatus::Fail; + } + catch (...) + { + return LastStatus = TestStatus::Crash; + } + } + + public: + std::string Name; + TestSuite& Link; + FMT::Detail::FileLocation Location; + TestStatus LastStatus; + }; + + struct TestStatusBank + { + void Reset() + { + TestsDone = 0; + TestsOk = 0; + TestsFail = 0; + TestsCrash = 0; + } + + void AddTestStatus(TestStatus status) + { + TestsDone++; + switch (status) + { + case TestStatus::Ok : TestsOk++; break; + case TestStatus::Fail : TestsFail++; break; + case TestStatus::Crash : TestsCrash++; break; + } + } + + void Add(TestStatusBank status) + { + TestsDone += status.TestsDone; + TestsOk += status.TestsOk; + TestsFail += status.TestsFail; + TestsCrash += status.TestsCrash; + } + + bool IsAllOk() { return TestsDone == TestsOk && TestsCrash == 0 && TestsFail == 0; } + + std::uint32_t ErrorStatus() { return TestsDone - TestsOk; } + + std::uint32_t TestsDone = 0; + std::uint32_t TestsOk = 0; + std::uint32_t TestsFail = 0; + std::uint32_t TestsCrash = 0; + }; + + class TestSuite; +} +namespace ProjectCore::Tester +{ + struct PerformanceTestData + { + bool Enable = false; + std::uint32_t NbSamples = 10; + }; + + struct ConcurenceSpecificationData + { + bool Enable = false; + }; + + class TestSuitesManager + { + public: + static bool ExecAllTestSuites(); + static inline std::unordered_map TestSuites; + + public: + static inline bool Verbose = false; + static inline bool PrintTime = false; + static inline PerformanceTestData PerformanceTest = PerformanceTestData{}; + static inline ConcurenceSpecificationData ConcurenceSpecification = ConcurenceSpecificationData{}; + }; +} +namespace ProjectCore::Tester::Detail +{ + struct TestSuiteData + { + bool Redirect_stdout = false; + bool Redirect_stdin = false; + bool Redirect_stderr = false; + }; + + class TestSuite + { + public: + TestSuite(std::string&& name, TestSuiteData extra = TestSuiteData{}, TestSuite* parent = nullptr) + : Name(std::move(name)) + , Tests() + , Extra(extra) + , Logger() + , TestLogger() + , Profiler(nullptr) + , Parent(parent) + { + if (parent == nullptr) + TestSuitesManager::TestSuites.insert({ Name, this }); + else + Parent->TestSuitesLinked.insert({ Name, this }); + } + + std::string Name; + std::unordered_map Tests; + std::unordered_map TestSuitesLinked; + + TestSuiteData Extra; + LoggerManager::BasicLogger Logger; + LoggerManager::BasicLogger TestLogger; + Instrumentation::Profiler* Profiler; + + TestSuite* Parent; + + public: + void InitLogger(); + + private: + std::string GetFullName(); + std::string GetCorrectedSizeName(); + Instrumentation::Profiler& GetProfiler(); + + public: + TestStatusBank ExecAllTests(); + }; +} + +namespace ProjectCore::FMT +{ + template + struct FormatterType + { + static void Format(const ProjectCore::Tester::Detail::TestSuite& t, FormatContext& context) + { + context.BufferOut().FastWriteString(t.Name); + } + }; + + template + struct FormatterType + { + static void Format(const ProjectCore::Tester::Detail::Test& t, FormatContext& context) { + context.BufferOut().FastWriteString(t.Link.Name); + context.BufferOut().FastWriteCharArray("::"); + context.BufferOut().FastWriteString(t.Name); + } + }; + + template + struct FormatterType + { + static void Format(const ProjectCore::Tester::TestStatus& status, FormatContext& context) { + switch (status) + { + case ProjectCore::Tester::TestStatus::Ok : context.SubContextArrayFMT("[ {C:green}OK{C} ]"); break; + case ProjectCore::Tester::TestStatus::Fail : context.SubContextArrayFMT("[ {C:red}FAIL{C} ]"); break; + case ProjectCore::Tester::TestStatus::Crash : context.SubContextArrayFMT("[{C:magenta}Crash{C} ]"); break; + } + } + }; + + template + struct FormatterType + { + static void Format(const ProjectCore::Tester::Detail::TestStatusBank& statusBank, FormatContext& context) { + context.BufferOut().FastWriteCharArray("TestsDone "); + context.SubContextArrayFMT("{:C:white}", statusBank.TestsDone); + + context.BufferOut().FastWriteCharArray(" | TestsOK "); + if (statusBank.TestsOk == statusBank.TestsDone) + context.SubContextArrayFMT("{:C:green}", statusBank.TestsOk); + else + context.SubContextArrayFMT("{:C:yellow}", statusBank.TestsOk); + + context.BufferOut().FastWriteCharArray(" | TestsFAIL "); + if (statusBank.TestsFail == 0) + context.SubContextArrayFMT("{:C:green}", statusBank.TestsFail); + else + context.SubContextArrayFMT("{:C:red}", statusBank.TestsFail); + + context.BufferOut().FastWriteCharArray(" | TestCrash "); + if (statusBank.TestsCrash == 0) + context.SubContextArrayFMT("{:C:green}", statusBank.TestsCrash); + else + context.SubContextArrayFMT("{:C:magenta}", statusBank.TestsCrash); + } + }; +} + +//-------------------- Base --------------------// +#define PROJECTCORE_TESTINTERNAL_SUITE_NAME(TestSuiteName) TestSuite_ ## TestSuiteName +#define PROJECTCORE_TESTINTERNAL_FUNC_NAME(TestSuiteName, TestName) TestSuite_ ## TestSuiteName ## TestName +#define PROJECTCORE_TESTINTERNAL_FUNC_EXEC_NAME(TestSuiteName, TestName) TestSuite_ ## TestSuiteName ## TestName ## _ExecMethod +#define PROJECTCORE_TESTINTERNAL_SUITE_EXTRA(...) ProjectCore::Tester::Detail::TestSuiteData{ __VA_ARGS__ } + +//-------------------- TestSuite --------------------// +#define PCT_TEST_SUITE(TestSuiteName, ...) ProjectCore::Tester::Detail::TestSuite PROJECTCORE_TESTINTERNAL_SUITE_NAME(TestSuiteName)(#TestSuiteName, PROJECTCORE_TESTINTERNAL_SUITE_EXTRA(__VA_ARGS__)) +#define PCT_TEST_GROUP(TestSuiteName, GroupName, ...) ProjectCore::Tester::Detail::TestSuite PROJECTCORE_TESTINTERNAL_SUITE_NAME(GroupName)(#GroupName, PROJECTCORE_TESTINTERNAL_SUITE_EXTRA(__VA_ARGS__), &PROJECTCORE_TESTINTERNAL_SUITE_NAME(TestSuiteName)) + +#define PCT_TEST_SUITE_DECLARATION(TestSuiteName, ...) ProjectCore::Tester::Detail::TestSuite PROJECTCORE_TESTINTERNAL_SUITE_NAME(TestSuiteName) +#define PCT_TEST_GROUP_DECLARATION(TestSuiteName, GroupName, ...) ProjectCore::Tester::Detail::TestSuite PROJECTCORE_TESTINTERNAL_SUITE_NAME(GroupName) diff --git a/src/ProjectCore/Tester/TestsUtilities/CopyMoveCheck.h b/src/ProjectCore/Tester/TestsUtilities/CopyMoveCheck.h new file mode 100644 index 0000000..1d757d6 --- /dev/null +++ b/src/ProjectCore/Tester/TestsUtilities/CopyMoveCheck.h @@ -0,0 +1,87 @@ +#pragma once + +#include "ProjectCore/LoggerManager/LoggerManager.h" + +namespace ProjectCore::Tester +{ + class CopyMoveCheck + { + public: + static inline LoggerManager::BasicLogger Logger; + + public: + CopyMoveCheck(const std::string& name) + : m_Name(name) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Default (copy string) Constructor", "TestCopy(const std::string& name)"); + } + + CopyMoveCheck(std::string&& name) + : m_Name(std::move(name)) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Default (move string) Constructor", "TestCopy(std::string&& name)"); + } + + + CopyMoveCheck(CopyMoveCheck& other) + : m_Name("Copy of " + other.m_Name) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Copy Constructor", "TestCopy(TestCopy&)"); + } + + CopyMoveCheck(const CopyMoveCheck& other) + : m_Name("Copy of " + other.m_Name) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Const Copy Constructor", "TestCopy(const TestCopy&)"); + } + + CopyMoveCheck(CopyMoveCheck&& other) noexcept + : m_Name("Move of " + other.m_Name) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Move Constructor", "TestCopy(TestCopy&&)"); + } + + CopyMoveCheck(const CopyMoveCheck&& other) noexcept + : m_Name("Move of " + other.m_Name) + { + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Const Move Constructor", "TestCopy(const TestCopy&&)"); + } + + + CopyMoveCheck& operator=(CopyMoveCheck& other) { + + m_Name = "Copy Of " + other.m_Name; + + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Copy Assignment", "TestCopy& operator=(TestCopy&)"); + return *this; + } + + CopyMoveCheck& operator=(const CopyMoveCheck& other) { + + m_Name = "Copy Of " + other.m_Name; + + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Const Copy Assignment", "TestCopy& operator=(const TestCopy&)"); + return *this; + } + + CopyMoveCheck& operator=(CopyMoveCheck&& other) noexcept { + + m_Name = "Move Of " + other.m_Name; + + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Move Assignment", "TestCopy& operator=(TestCopy&&)"); + return *this; + } + + CopyMoveCheck& operator=(const CopyMoveCheck&& other) noexcept { + + m_Name = "Move Of " + other.m_Name; + + Logger.Info("CopyMoveCheck {} : {:C:red} ( {:C:red} )", m_Name, "Const Move Assignment", "TestCopy& operator=(const TestCopy&&)"); + return *this; + } + + private: + std::string m_Name; + }; +} + diff --git a/src/ProjectCore/Tester/TestsUtilities/TestsMacros.h b/src/ProjectCore/Tester/TestsUtilities/TestsMacros.h new file mode 100644 index 0000000..18a9b77 --- /dev/null +++ b/src/ProjectCore/Tester/TestsUtilities/TestsMacros.h @@ -0,0 +1,69 @@ +#pragma once + +#include "ProjectCore/LoggerManager/LoggerManager.h" + +#define PROJECTCORE_TEST_TRACE(...) ProjectCore::Test::TestCore::GetLogger().Trace(__VA_ARGS__) +#define PROJECTCORE_TEST_INFO(...) ProjectCore::Test::TestCore::GetLogger().Info(__VA_ARGS__) +#define PROJECTCORE_TEST_WARN(...) ProjectCore::Test::TestCore::GetLogger().Warn(__VA_ARGS__) +#define PROJECTCORE_TEST_ERROR(...) ProjectCore::Test::TestCore::GetLogger().Error(__VA_ARGS__) +#define PROJECTCORE_TEST_FATAL(...) ProjectCore::Test::TestCore::GetLogger().Fatal(__VA_ARGS__) +#define PROJECTCORE_TEST_OK(...) ProjectCore::Test::TestCore::GetLogger().Ok(__VA_ARGS__) +#define PROJECTCORE_TEST_FAIL(...) ProjectCore::Test::TestCore::GetLogger().Fail(__VA_ARGS__) +#define PROJECTCORE_TEST_BASIC(...) ProjectCore::Test::TestCore::GetLogger().Basic(__VA_ARGS__) + +namespace ProjectCore::Test +{ + class TestCore + { + public: + static LoggerManager::BasicLogger& GetLogger() { static LoggerManager::BasicLogger instance("ProjectCore-Test", "{name} {color} -> {data}"); return instance; } + }; +} + +// Assert log if false +#define PROJECTCORE_TEST_ASSERT(x) if(!(x)) PROJECTCORE_TEST_FAIL("ASSERT FAIL : {0:C:red}", #x) + +// Check if false +#define PROJECTCORE_TEST_TEST(x) if(x) PROJECTCORE_TEST_OK("TEST OK : {:C:green}", #x);\ + else PROJECTCORE_TEST_FAIL("TEST FAIL : {:C:red}", #x) + +// Check if equal with file printed +#define PROJECTCORE_TEST_EQ(x, y) if(x == y) PROJECTCORE_TEST_OK("{C:green}{} == {}", #x, #y);\ + else PROJECTCORE_TEST_FAIL("{C:red}{} == {}", #x, #y) + +// Check if not equal with file printed +#define PROJECTCORE_TEST_NEQ(x, y) if(x != y) PROJECTCORE_TEST_OK("{C:green}{} != {}", #x, #y);\ + else PROJECTCORE_TEST_FAIL("{C:red}{} != {}", #x, #y) + + +#define PROJECTCORE_TEST_FN(fn, resExpected) {\ + auto res = fn;\ + if (res == resExpected) PROJECTCORE_TEST_OK("{C:green}{} return {}", #fn, res); \ + else PROJECTCORE_TEST_FAIL("{C:red}{} return {} instead of {}", #fn, res, resExpected); \ + } + +#define PROJECTCORE_TEST_FNFMT(fn, resExpected, ...) {\ + PROJECTCORE_TEST_INFO(__VA_ARGS__);\ + auto res = fn;\ + if (res == resExpected) PROJECTCORE_TEST_OK("{C:green}{} return {}", #fn, res); \ + else PROJECTCORE_TEST_FAIL("{C:red}{} return {} instead of {}", #fn, res, resExpected); \ + } + + +#ifdef PROJECTCORE_ECTM_ENABLE + +#define ECTM_ASSERT(x) PROJECTCORE_TEST_ASSERT(x) +#define ECTM_TEST(x) PROJECTCORE_TEST_TEST(x) +#define ECTM_EQ(x, y) PROJECTCORE_TEST_EQ(x, y) +#define ECTM_NEQ(x, y) PROJECTCORE_TEST_NEQ(x, y) +#define ECTM_FN(fn, resExpected) PROJECTCORE_TEST_FN(fn, resExpected) +#define ECTM_FNFMT(fn, resExpected, ...) PROJECTCORE_TEST_FNFMT(fn, resExpected, __VA_ARGS__) + +#endif /* PROJECTCORE_ECTM_ENABLE */ + +//******************************************************// +//******************************************************// +//******************************************************// + +// Check if false at compile time +#define PROJECTCORE_TEST_STATIC_ASSERT(x) static_assert(x, "ASSERT ERROR : " #x) diff --git a/src/ProjectCore/Tools/MapMacro.h b/src/ProjectCore/Tools/MapMacro.h new file mode 100644 index 0000000..3b3fa45 --- /dev/null +++ b/src/ProjectCore/Tools/MapMacro.h @@ -0,0 +1,15 @@ +#pragma once + +// From : https://www.scs.stanford.edu/~dm/blog/va-opt.html + +#define PARENS () + +#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__)))) +#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__)))) +#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__)))) +#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__)))) +#define EXPAND1(...) __VA_ARGS__ + +#define FOR_EACH(macro, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__))) +#define FOR_EACH_HELPER(macro, a1, ...) macro(a1) __VA_OPT__(, FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__)) +#define FOR_EACH_AGAIN() FOR_EACH_HELPER